Mercurial > hg > CbC > CbC_llvm
comparison clang/docs/ObjectiveCLiterals.rst @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
147:c2174574ed3a | 150:1d019706d866 |
---|---|
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. |