1 | ==================== |
2 | Objective-C Literals |
3 | ==================== |
4 | |
5 | Introduction |
6 | ============ |
7 | |
8 | Three new features were introduced into clang at the same time: |
9 | *NSNumber Literals* provide a syntax for creating ``NSNumber`` from |
10 | scalar literal expressions; *Collection Literals* provide a short-hand |
11 | for creating arrays and dictionaries; *Object Subscripting* provides a |
12 | way to use subscripting with Objective-C objects. Users of Apple |
13 | compiler releases can use these features starting with the Apple LLVM |
14 | Compiler 4.0. Users of open-source LLVM.org compiler releases can use |
15 | these features starting with clang v3.1. |
16 | |
17 | These language additions simplify common Objective-C programming |
18 | patterns, make programs more concise, and improve the safety of |
19 | container creation. |
20 | |
21 | This document describes how the features are implemented in clang, and |
22 | how to use them in your own programs. |
23 | |
24 | NSNumber Literals |
25 | ================= |
26 | |
27 | The framework class ``NSNumber`` is used to wrap scalar values inside |
28 | objects: signed and unsigned integers (``char``, ``short``, ``int``, |
29 | ``long``, ``long long``), floating point numbers (``float``, |
30 | ``double``), and boolean values (``BOOL``, C++ ``bool``). Scalar values |
31 | wrapped in objects are also known as *boxed* values. |
32 | |
33 | In Objective-C, any character, numeric or boolean literal prefixed with |
34 | the ``'@'`` character will evaluate to a pointer to an ``NSNumber`` |
35 | object initialized with that value. C's type suffixes may be used to |
36 | control the size of numeric literals. |
37 | |
38 | Examples |
39 | -------- |
40 | |
41 | The following program illustrates the rules for ``NSNumber`` literals: |
42 | |
43 | .. code-block:: objc |
44 | |
45 | void main(int argc, const char *argv[]) { |
46 | // character literals. |
47 | NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z'] |
48 | |
49 | // integral literals. |
50 | NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42] |
51 | NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U] |
52 | NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L] |
53 | NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL] |
54 | |
55 | // floating point literals. |
56 | NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F] |
57 | NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535] |
58 | |
59 | // BOOL literals. |
60 | NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES] |
61 | NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO] |
62 | |
63 | #ifdef __cplusplus |
64 | NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true] |
65 | NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false] |
66 | #endif |
67 | } |
68 | |
69 | Discussion |
70 | ---------- |
71 | |
72 | NSNumber literals only support literal scalar values after the ``'@'``. |
73 | Consequently, ``@INT_MAX`` works, but ``@INT_MIN`` does not, because |
74 | they are defined like this: |
75 | |
76 | .. code-block:: objc |
77 | |
78 | #define INT_MAX 2147483647 /* max value for an int */ |
79 | #define INT_MIN (-2147483647-1) /* min value for an int */ |
80 | |
81 | The definition of ``INT_MIN`` is not a simple literal, but a |
82 | parenthesized expression. Parenthesized expressions are supported using |
83 | the `boxed expression <#objc_boxed_expressions>`_ syntax, which is |
84 | described in the next section. |
85 | |
86 | Because ``NSNumber`` does not currently support wrapping ``long double`` |
87 | values, the use of a ``long double NSNumber`` literal (e.g. |
88 | ``@123.23L``) will be rejected by the compiler. |
89 | |
90 | Previously, the ``BOOL`` type was simply a typedef for ``signed char``, |
91 | and ``YES`` and ``NO`` were macros that expand to ``(BOOL)1`` and |
92 | ``(BOOL)0`` respectively. To support ``@YES`` and ``@NO`` expressions, |
93 | these macros are now defined using new language keywords in |
94 | ``<objc/objc.h>``: |
95 | |
96 | .. code-block:: objc |
97 | |
98 | #if __has_feature(objc_bool) |
99 | #define YES __objc_yes |
100 | #define NO __objc_no |
101 | #else |
102 | #define YES ((BOOL)1) |
103 | #define NO ((BOOL)0) |
104 | #endif |
105 | |
106 | The compiler implicitly converts ``__objc_yes`` and ``__objc_no`` to |
107 | ``(BOOL)1`` and ``(BOOL)0``. The keywords are used to disambiguate |
108 | ``BOOL`` and integer literals. |
109 | |
110 | Objective-C++ also supports ``@true`` and ``@false`` expressions, which |
111 | are equivalent to ``@YES`` and ``@NO``. |
112 | |
113 | Boxed Expressions |
114 | ================= |
115 | |
116 | Objective-C provides a new syntax for boxing C expressions: |
117 | |
118 | .. code-block:: objc |
119 | |
120 | @( <expression> ) |
121 | |
122 | Expressions of scalar (numeric, enumerated, BOOL), C string pointer |
123 | and some C structures (via NSValue) are supported: |
124 | |
125 | .. code-block:: objc |
126 | |
127 | // numbers. |
128 | NSNumber *smallestInt = @(-INT_MAX - 1); // [NSNumber numberWithInt:(-INT_MAX - 1)] |
129 | NSNumber *piOverTwo = @(M_PI / 2); // [NSNumber numberWithDouble:(M_PI / 2)] |
130 | |
131 | // enumerated types. |
132 | typedef enum { Red, Green, Blue } Color; |
133 | NSNumber *favoriteColor = @(Green); // [NSNumber numberWithInt:((int)Green)] |
134 | |
135 | // strings. |
136 | NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))] |
137 | NSArray *pathComponents = [path componentsSeparatedByString:@":"]; |
138 | |
139 | // structs. |
140 | NSValue *center = @(view.center); // Point p = view.center; |
141 | // [NSValue valueWithBytes:&p objCType:@encode(Point)]; |
142 | NSValue *frame = @(view.frame); // Rect r = view.frame; |
143 | // [NSValue valueWithBytes:&r objCType:@encode(Rect)]; |
144 | |
145 | Boxed Enums |
146 | ----------- |
147 | |
148 | Cocoa frameworks frequently define constant values using *enums.* |
149 | Although enum values are integral, they may not be used directly as |
150 | boxed literals (this avoids conflicts with future ``'@'``-prefixed |
151 | Objective-C keywords). Instead, an enum value must be placed inside a |
152 | boxed expression. The following example demonstrates configuring an |
153 | ``AVAudioRecorder`` using a dictionary that contains a boxed enumeration |
154 | value: |
155 | |
156 | .. code-block:: objc |
157 | |
158 | enum { |
159 | AVAudioQualityMin = 0, |
160 | AVAudioQualityLow = 0x20, |
161 | AVAudioQualityMedium = 0x40, |
162 | AVAudioQualityHigh = 0x60, |
163 | AVAudioQualityMax = 0x7F |
164 | }; |
165 | |
166 | - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL { |
167 | NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) }; |
168 | return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL]; |
169 | } |
170 | |
171 | The expression ``@(AVAudioQualityMax)`` converts ``AVAudioQualityMax`` |
172 | to an integer type, and boxes the value accordingly. If the enum has a |
173 | :ref:`fixed underlying type <objc-fixed-enum>` as in: |
174 | |
175 | .. code-block:: objc |
176 | |
177 | typedef enum : unsigned char { Red, Green, Blue } Color; |
178 | NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:] |
179 | |
180 | then the fixed underlying type will be used to select the correct |
181 | ``NSNumber`` creation method. |
182 | |
183 | Boxing a value of enum type will result in a ``NSNumber`` pointer with a |
184 | creation method according to the underlying type of the enum, which can |
185 | be a :ref:`fixed underlying type <objc-fixed-enum>` |
186 | or a compiler-defined integer type capable of representing the values of |
187 | all the members of the enumeration: |
188 | |
189 | .. code-block:: objc |
190 | |
191 | typedef enum : unsigned char { Red, Green, Blue } Color; |
192 | Color col = Red; |
193 | NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:] |
194 | |
195 | Boxed C Strings |
196 | --------------- |
197 | |
198 | A C string literal prefixed by the ``'@'`` token denotes an ``NSString`` |
199 | literal in the same way a numeric literal prefixed by the ``'@'`` token |
200 | denotes an ``NSNumber`` literal. When the type of the parenthesized |
201 | expression is ``(char *)`` or ``(const char *)``, the result of the |
202 | boxed expression is a pointer to an ``NSString`` object containing |
203 | equivalent character data, which is assumed to be '\\0'-terminated and |
204 | UTF-8 encoded. The following example converts C-style command line |
205 | arguments into ``NSString`` objects. |
206 | |
207 | .. code-block:: objc |
208 | |
209 | // Partition command line arguments into positional and option arguments. |
210 | NSMutableArray *args = [NSMutableArray new]; |
211 | NSMutableDictionary *options = [NSMutableDictionary new]; |
212 | while (--argc) { |
213 | const char *arg = *++argv; |
214 | if (strncmp(arg, "--", 2) == 0) { |
215 | options[@(arg + 2)] = @(*++argv); // --key value |
216 | } else { |
217 | [args addObject:@(arg)]; // positional argument |
218 | } |
219 | } |
220 | |
221 | As with all C pointers, character pointer expressions can involve |
222 | arbitrary pointer arithmetic, therefore programmers must ensure that the |
223 | character data is valid. Passing ``NULL`` as the character pointer will |
224 | raise an exception at runtime. When possible, the compiler will reject |
225 | ``NULL`` character pointers used in boxed expressions. |
226 | |
227 | Boxed C Structures |
228 | ------------------ |
229 | |
230 | Boxed expressions support construction of NSValue objects. |
231 | It said that C structures can be used, the only requirement is: |
232 | structure should be marked with ``objc_boxable`` attribute. |
233 | To support older version of frameworks and/or third-party libraries |
234 | you may need to add the attribute via ``typedef``. |
235 | |
236 | .. code-block:: objc |
237 | |
238 | struct __attribute__((objc_boxable)) Point { |
239 | // ... |
240 | }; |
241 | |
242 | typedef struct __attribute__((objc_boxable)) _Size { |
243 | // ... |
244 | } Size; |
245 | |
246 | typedef struct _Rect { |
247 | // ... |
248 | } Rect; |
249 | |
250 | struct Point p; |
251 | NSValue *point = @(p); // ok |
252 | Size s; |
253 | NSValue *size = @(s); // ok |
254 | |
255 | Rect r; |
256 | NSValue *bad_rect = @(r); // error |
257 | |
258 | typedef struct __attribute__((objc_boxable)) _Rect Rect; |
259 | |
260 | NSValue *good_rect = @(r); // ok |
261 | |
262 | |
263 | Container Literals |
264 | ================== |
265 | |
266 | Objective-C now supports a new expression syntax for creating immutable |
267 | array and dictionary container objects. |
268 | |
269 | Examples |
270 | -------- |
271 | |
272 | Immutable array expression: |
273 | |
274 | .. code-block:: objc |
275 | |
276 | NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ]; |
277 | |
278 | This creates an ``NSArray`` with 3 elements. The comma-separated |
279 | sub-expressions of an array literal can be any Objective-C object |
280 | pointer typed expression. |
281 | |
282 | Immutable dictionary expression: |
283 | |
284 | .. code-block:: objc |
285 | |
286 | NSDictionary *dictionary = @{ |
287 | @"name" : NSUserName(), |
288 | @"date" : [NSDate date], |
289 | @"processInfo" : [NSProcessInfo processInfo] |
290 | }; |
291 | |
292 | This creates an ``NSDictionary`` with 3 key/value pairs. Value |
293 | sub-expressions of a dictionary literal must be Objective-C object |
294 | pointer typed, as in array literals. Key sub-expressions must be of an |
295 | Objective-C object pointer type that implements the |
296 | ``<NSCopying>`` protocol. |
297 | |
298 | Discussion |
299 | ---------- |
300 | |
301 | Neither keys nor values can have the value ``nil`` in containers. If the |
302 | compiler can prove that a key or value is ``nil`` at compile time, then |
303 | a warning will be emitted. Otherwise, a runtime error will occur. |
304 | |
305 | Using array and dictionary literals is safer than the variadic creation |
306 | forms commonly in use today. Array literal expressions expand to calls |
307 | to ``+[NSArray arrayWithObjects:count:]``, which validates that all |
308 | objects are non-``nil``. The variadic form, |
309 | ``+[NSArray arrayWithObjects:]`` uses ``nil`` as an argument list |
310 | terminator, which can lead to malformed array objects. Dictionary |
311 | literals are similarly created with |
312 | ``+[NSDictionary dictionaryWithObjects:forKeys:count:]`` which validates |
313 | all objects and keys, unlike |
314 | ``+[NSDictionary dictionaryWithObjectsAndKeys:]`` which also uses a |
315 | ``nil`` parameter as an argument list terminator. |
316 | |
317 | Object Subscripting |
318 | =================== |
319 | |
320 | Objective-C object pointer values can now be used with C's subscripting |
321 | operator. |
322 | |
323 | Examples |
324 | -------- |
325 | |
326 | The following code demonstrates the use of object subscripting syntax |
327 | with ``NSMutableArray`` and ``NSMutableDictionary`` objects: |
328 | |
329 | .. code-block:: objc |
330 | |
331 | NSMutableArray *array = ...; |
332 | NSUInteger idx = ...; |
333 | id newObject = ...; |
334 | id oldObject = array[idx]; |
335 | array[idx] = newObject; // replace oldObject with newObject |
336 | |
337 | NSMutableDictionary *dictionary = ...; |
338 | NSString *key = ...; |
339 | oldObject = dictionary[key]; |
340 | dictionary[key] = newObject; // replace oldObject with newObject |
341 | |
342 | The next section explains how subscripting expressions map to accessor |
343 | methods. |
344 | |
345 | Subscripting Methods |
346 | -------------------- |
347 | |
348 | Objective-C supports two kinds of subscript expressions: *array-style* |
349 | subscript expressions use integer typed subscripts; *dictionary-style* |
350 | subscript expressions use Objective-C object pointer typed subscripts. |
351 | Each type of subscript expression is mapped to a message send using a |
352 | predefined selector. The advantage of this design is flexibility: class |
353 | designers are free to introduce subscripting by declaring methods or by |
354 | adopting protocols. Moreover, because the method names are selected by |
355 | the type of the subscript, an object can be subscripted using both array |
356 | and dictionary styles. |
357 | |
358 | Array-Style Subscripting |
359 | ^^^^^^^^^^^^^^^^^^^^^^^^ |
360 | |
361 | When the subscript operand has an integral type, the expression is |
362 | rewritten to use one of two different selectors, depending on whether |
363 | the element is being read or written. When an expression reads an |
364 | element using an integral index, as in the following example: |
365 | |
366 | .. code-block:: objc |
367 | |
368 | NSUInteger idx = ...; |
369 | id value = object[idx]; |
370 | |
371 | it is translated into a call to ``objectAtIndexedSubscript:`` |
372 | |
373 | .. code-block:: objc |
374 | |
375 | id value = [object objectAtIndexedSubscript:idx]; |
376 | |
377 | When an expression writes an element using an integral index: |
378 | |
379 | .. code-block:: objc |
380 | |
381 | object[idx] = newValue; |
382 | |
383 | it is translated to a call to ``setObject:atIndexedSubscript:`` |
384 | |
385 | .. code-block:: objc |
386 | |
387 | [object setObject:newValue atIndexedSubscript:idx]; |
388 | |
389 | These message sends are then type-checked and performed just like |
390 | explicit message sends. The method used for objectAtIndexedSubscript: |
391 | must be declared with an argument of integral type and a return value of |
392 | some Objective-C object pointer type. The method used for |
393 | setObject:atIndexedSubscript: must be declared with its first argument |
394 | having some Objective-C pointer type and its second argument having |
395 | integral type. |
396 | |
397 | The meaning of indexes is left up to the declaring class. The compiler |
398 | will coerce the index to the appropriate argument type of the method it |
399 | uses for type-checking. For an instance of ``NSArray``, reading an |
400 | element using an index outside the range ``[0, array.count)`` will raise |
401 | an exception. For an instance of ``NSMutableArray``, assigning to an |
402 | element using an index within this range will replace that element, but |
403 | assigning to an element using an index outside this range will raise an |
404 | exception; no syntax is provided for inserting, appending, or removing |
405 | elements for mutable arrays. |
406 | |
407 | A class need not declare both methods in order to take advantage of this |
408 | language feature. For example, the class ``NSArray`` declares only |
409 | ``objectAtIndexedSubscript:``, so that assignments to elements will fail |
410 | to type-check; moreover, its subclass ``NSMutableArray`` declares |
411 | ``setObject:atIndexedSubscript:``. |
412 | |
413 | Dictionary-Style Subscripting |
414 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
415 | |
416 | When the subscript operand has an Objective-C object pointer type, the |
417 | expression is rewritten to use one of two different selectors, depending |
418 | on whether the element is being read from or written to. When an |
419 | expression reads an element using an Objective-C object pointer |
420 | subscript operand, as in the following example: |
421 | |
422 | .. code-block:: objc |
423 | |
424 | id key = ...; |
425 | id value = object[key]; |
426 | |
427 | it is translated into a call to the ``objectForKeyedSubscript:`` method: |
428 | |
429 | .. code-block:: objc |
430 | |
431 | id value = [object objectForKeyedSubscript:key]; |
432 | |
433 | When an expression writes an element using an Objective-C object pointer |
434 | subscript: |
435 | |
436 | .. code-block:: objc |
437 | |
438 | object[key] = newValue; |
439 | |
440 | it is translated to a call to ``setObject:forKeyedSubscript:`` |
441 | |
442 | .. code-block:: objc |
443 | |
444 | [object setObject:newValue forKeyedSubscript:key]; |
445 | |
446 | The behavior of ``setObject:forKeyedSubscript:`` is class-specific; but |
447 | in general it should replace an existing value if one is already |
448 | associated with a key, otherwise it should add a new value for the key. |
449 | No syntax is provided for removing elements from mutable dictionaries. |
450 | |
451 | Discussion |
452 | ---------- |
453 | |
454 | An Objective-C subscript expression occurs when the base operand of the |
455 | C subscript operator has an Objective-C object pointer type. Since this |
456 | potentially collides with pointer arithmetic on the value, these |
457 | expressions are only supported under the modern Objective-C runtime, |
458 | which categorically forbids such arithmetic. |
459 | |
460 | Currently, only subscripts of integral or Objective-C object pointer |
461 | type are supported. In C++, a class type can be used if it has a single |
462 | conversion function to an integral or Objective-C pointer type, in which |
463 | case that conversion is applied and analysis continues as appropriate. |
464 | Otherwise, the expression is ill-formed. |
465 | |
466 | An Objective-C object subscript expression is always an l-value. If the |
467 | expression appears on the left-hand side of a simple assignment operator |
468 | (=), the element is written as described below. If the expression |
469 | appears on the left-hand side of a compound assignment operator (e.g. |
470 | +=), the program is ill-formed, because the result of reading an element |
471 | is always an Objective-C object pointer and no binary operators are |
472 | legal on such pointers. If the expression appears in any other position, |
473 | the element is read as described below. It is an error to take the |
474 | address of a subscript expression, or (in C++) to bind a reference to |
475 | it. |
476 | |
477 | Programs can use object subscripting with Objective-C object pointers of |
478 | type ``id``. Normal dynamic message send rules apply; the compiler must |
479 | see *some* declaration of the subscripting methods, and will pick the |
480 | declaration seen first. |
481 | |
482 | Caveats |
483 | ======= |
484 | |
485 | Objects created using the literal or boxed expression syntax are not |
486 | guaranteed to be uniqued by the runtime, but nor are they guaranteed to |
487 | be newly-allocated. As such, the result of performing direct comparisons |
488 | against the location of an object literal (using ``==``, ``!=``, ``<``, |
489 | ``<=``, ``>``, or ``>=``) is not well-defined. This is usually a simple |
490 | mistake in code that intended to call the ``isEqual:`` method (or the |
491 | ``compare:`` method). |
492 | |
493 | This caveat applies to compile-time string literals as well. |
494 | Historically, string literals (using the ``@"..."`` syntax) have been |
495 | uniqued across translation units during linking. This is an |
496 | implementation detail of the compiler and should not be relied upon. If |
497 | you are using such code, please use global string constants instead |
498 | (``NSString * const MyConst = @"..."``) or use ``isEqual:``. |
499 | |
500 | Grammar Additions |
501 | ================= |
502 | |
503 | To support the new syntax described above, the Objective-C |
504 | ``@``-expression grammar has the following new productions: |
505 | |
506 | :: |
507 | |
508 | objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal) |
509 | ; |
510 | |
511 | object-literal : ('+' | '-')? numeric-constant |
512 | | character-constant |
513 | | boolean-constant |
514 | | array-literal |
515 | | dictionary-literal |
516 | ; |
517 | |
518 | boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */ |
519 | ; |
520 | |
521 | array-literal : '[' assignment-expression-list ']' |
522 | ; |
523 | |
524 | assignment-expression-list : assignment-expression (',' assignment-expression-list)? |
525 | | /* empty */ |
526 | ; |
527 | |
528 | dictionary-literal : '{' key-value-list '}' |
529 | ; |
530 | |
531 | key-value-list : key-value-pair (',' key-value-list)? |
532 | | /* empty */ |
533 | ; |
534 | |
535 | key-value-pair : assignment-expression ':' assignment-expression |
536 | ; |
537 | |
538 | Note: ``@true`` and ``@false`` are only supported in Objective-C++. |
539 | |
540 | Availability Checks |
541 | =================== |
542 | |
543 | Programs test for the new features by using clang's \_\_has\_feature |
544 | checks. Here are examples of their use: |
545 | |
546 | .. code-block:: objc |
547 | |
548 | #if __has_feature(objc_array_literals) |
549 | // new way. |
550 | NSArray *elements = @[ @"H", @"He", @"O", @"C" ]; |
551 | #else |
552 | // old way (equivalent). |
553 | id objects[] = { @"H", @"He", @"O", @"C" }; |
554 | NSArray *elements = [NSArray arrayWithObjects:objects count:4]; |
555 | #endif |
556 | |
557 | #if __has_feature(objc_dictionary_literals) |
558 | // new way. |
559 | NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 }; |
560 | #else |
561 | // old way (equivalent). |
562 | id keys[] = { @"H", @"He", @"O", @"C" }; |
563 | id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026], |
564 | [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] }; |
565 | NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4]; |
566 | #endif |
567 | |
568 | #if __has_feature(objc_subscripting) |
569 | NSUInteger i, count = elements.count; |
570 | for (i = 0; i < count; ++i) { |
571 | NSString *element = elements[i]; |
572 | NSNumber *mass = masses[element]; |
573 | NSLog(@"the mass of %@ is %@", element, mass); |
574 | } |
575 | #else |
576 | NSUInteger i, count = [elements count]; |
577 | for (i = 0; i < count; ++i) { |
578 | NSString *element = [elements objectAtIndex:i]; |
579 | NSNumber *mass = [masses objectForKey:element]; |
580 | NSLog(@"the mass of %@ is %@", element, mass); |
581 | } |
582 | #endif |
583 | |
584 | #if __has_attribute(objc_boxable) |
585 | typedef struct __attribute__((objc_boxable)) _Rect Rect; |
586 | #endif |
587 | |
588 | #if __has_feature(objc_boxed_nsvalue_expressions) |
589 | CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"]; |
590 | animation.fromValue = @(layer.position); |
591 | animation.toValue = @(newPosition); |
592 | [layer addAnimation:animation forKey:@"move"]; |
593 | #else |
594 | CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"]; |
595 | animation.fromValue = [NSValue valueWithCGPoint:layer.position]; |
596 | animation.toValue = [NSValue valueWithCGPoint:newPosition]; |
597 | [layer addAnimation:animation forKey:@"move"]; |
598 | #endif |
599 | |
600 | Code can use also ``__has_feature(objc_bool)`` to check for the |
601 | availability of numeric literals support. This checks for the new |
602 | ``__objc_yes / __objc_no`` keywords, which enable the use of |
603 | ``@YES / @NO`` literals. |
604 | |
605 | To check whether boxed expressions are supported, use |
606 | ``__has_feature(objc_boxed_expressions)`` feature macro. |
607 | |