Sean Silva | f3a1ff3 | 2012-12-21 00:17:02 +0000 | [diff] [blame] | 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) and C string pointer |
| 123 | types 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 | Boxed Enums |
| 140 | ----------- |
| 141 | |
| 142 | Cocoa frameworks frequently define constant values using *enums.* |
| 143 | Although enum values are integral, they may not be used directly as |
| 144 | boxed literals (this avoids conflicts with future ``'@'``-prefixed |
| 145 | Objective-C keywords). Instead, an enum value must be placed inside a |
| 146 | boxed expression. The following example demonstrates configuring an |
| 147 | ``AVAudioRecorder`` using a dictionary that contains a boxed enumeration |
| 148 | value: |
| 149 | |
| 150 | .. code-block:: objc |
| 151 | |
| 152 | enum { |
| 153 | AVAudioQualityMin = 0, |
| 154 | AVAudioQualityLow = 0x20, |
| 155 | AVAudioQualityMedium = 0x40, |
| 156 | AVAudioQualityHigh = 0x60, |
| 157 | AVAudioQualityMax = 0x7F |
| 158 | }; |
| 159 | |
| 160 | - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL { |
| 161 | NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) }; |
| 162 | return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL]; |
| 163 | } |
| 164 | |
| 165 | The expression ``@(AVAudioQualityMax)`` converts ``AVAudioQualityMax`` |
| 166 | to an integer type, and boxes the value accordingly. If the enum has a |
Sean Silva | 159cc9e | 2013-01-02 13:07:47 +0000 | [diff] [blame] | 167 | :ref:`fixed underlying type <objc-fixed-enum>` as in: |
Sean Silva | f3a1ff3 | 2012-12-21 00:17:02 +0000 | [diff] [blame] | 168 | |
| 169 | .. code-block:: objc |
| 170 | |
| 171 | typedef enum : unsigned char { Red, Green, Blue } Color; |
| 172 | NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:] |
| 173 | |
| 174 | then the fixed underlying type will be used to select the correct |
| 175 | ``NSNumber`` creation method. |
| 176 | |
| 177 | Boxing a value of enum type will result in a ``NSNumber`` pointer with a |
| 178 | creation method according to the underlying type of the enum, which can |
Sean Silva | 159cc9e | 2013-01-02 13:07:47 +0000 | [diff] [blame] | 179 | be a :ref:`fixed underlying type <objc-fixed-enum>` |
Sean Silva | f3a1ff3 | 2012-12-21 00:17:02 +0000 | [diff] [blame] | 180 | or a compiler-defined integer type capable of representing the values of |
| 181 | all the members of the enumeration: |
| 182 | |
| 183 | .. code-block:: objc |
| 184 | |
| 185 | typedef enum : unsigned char { Red, Green, Blue } Color; |
| 186 | Color col = Red; |
| 187 | NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:] |
| 188 | |
| 189 | Boxed C Strings |
| 190 | --------------- |
| 191 | |
| 192 | A C string literal prefixed by the ``'@'`` token denotes an ``NSString`` |
| 193 | literal in the same way a numeric literal prefixed by the ``'@'`` token |
| 194 | denotes an ``NSNumber`` literal. When the type of the parenthesized |
| 195 | expression is ``(char *)`` or ``(const char *)``, the result of the |
| 196 | boxed expression is a pointer to an ``NSString`` object containing |
| 197 | equivalent character data, which is assumed to be '\\0'-terminated and |
| 198 | UTF-8 encoded. The following example converts C-style command line |
| 199 | arguments into ``NSString`` objects. |
| 200 | |
| 201 | .. code-block:: objc |
| 202 | |
| 203 | // Partition command line arguments into positional and option arguments. |
| 204 | NSMutableArray *args = [NSMutableArray new]; |
| 205 | NSMutableDictionary *options = [NSMutableDictionary new]; |
| 206 | while (--argc) { |
| 207 | const char *arg = *++argv; |
| 208 | if (strncmp(arg, "--", 2) == 0) { |
| 209 | options[@(arg + 2)] = @(*++argv); // --key value |
| 210 | } else { |
| 211 | [args addObject:@(arg)]; // positional argument |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | As with all C pointers, character pointer expressions can involve |
| 216 | arbitrary pointer arithmetic, therefore programmers must ensure that the |
| 217 | character data is valid. Passing ``NULL`` as the character pointer will |
| 218 | raise an exception at runtime. When possible, the compiler will reject |
| 219 | ``NULL`` character pointers used in boxed expressions. |
| 220 | |
Sean Silva | f3a1ff3 | 2012-12-21 00:17:02 +0000 | [diff] [blame] | 221 | Container Literals |
| 222 | ================== |
| 223 | |
| 224 | Objective-C now supports a new expression syntax for creating immutable |
| 225 | array and dictionary container objects. |
| 226 | |
| 227 | Examples |
| 228 | -------- |
| 229 | |
| 230 | Immutable array expression: |
| 231 | |
| 232 | .. code-block:: objc |
| 233 | |
| 234 | NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ]; |
| 235 | |
| 236 | This creates an ``NSArray`` with 3 elements. The comma-separated |
| 237 | sub-expressions of an array literal can be any Objective-C object |
| 238 | pointer typed expression. |
| 239 | |
| 240 | Immutable dictionary expression: |
| 241 | |
| 242 | .. code-block:: objc |
| 243 | |
| 244 | NSDictionary *dictionary = @{ |
| 245 | @"name" : NSUserName(), |
| 246 | @"date" : [NSDate date], |
| 247 | @"processInfo" : [NSProcessInfo processInfo] |
| 248 | }; |
| 249 | |
| 250 | This creates an ``NSDictionary`` with 3 key/value pairs. Value |
| 251 | sub-expressions of a dictionary literal must be Objective-C object |
| 252 | pointer typed, as in array literals. Key sub-expressions must be of an |
| 253 | Objective-C object pointer type that implements the |
| 254 | ``<NSCopying>`` protocol. |
| 255 | |
| 256 | Discussion |
| 257 | ---------- |
| 258 | |
| 259 | Neither keys nor values can have the value ``nil`` in containers. If the |
| 260 | compiler can prove that a key or value is ``nil`` at compile time, then |
| 261 | a warning will be emitted. Otherwise, a runtime error will occur. |
| 262 | |
| 263 | Using array and dictionary literals is safer than the variadic creation |
| 264 | forms commonly in use today. Array literal expressions expand to calls |
| 265 | to ``+[NSArray arrayWithObjects:count:]``, which validates that all |
| 266 | objects are non-``nil``. The variadic form, |
| 267 | ``+[NSArray arrayWithObjects:]`` uses ``nil`` as an argument list |
| 268 | terminator, which can lead to malformed array objects. Dictionary |
| 269 | literals are similarly created with |
| 270 | ``+[NSDictionary dictionaryWithObjects:forKeys:count:]`` which validates |
| 271 | all objects and keys, unlike |
| 272 | ``+[NSDictionary dictionaryWithObjectsAndKeys:]`` which also uses a |
| 273 | ``nil`` parameter as an argument list terminator. |
| 274 | |
| 275 | Object Subscripting |
| 276 | =================== |
| 277 | |
| 278 | Objective-C object pointer values can now be used with C's subscripting |
| 279 | operator. |
| 280 | |
| 281 | Examples |
| 282 | -------- |
| 283 | |
| 284 | The following code demonstrates the use of object subscripting syntax |
| 285 | with ``NSMutableArray`` and ``NSMutableDictionary`` objects: |
| 286 | |
| 287 | .. code-block:: objc |
| 288 | |
| 289 | NSMutableArray *array = ...; |
| 290 | NSUInteger idx = ...; |
| 291 | id newObject = ...; |
| 292 | id oldObject = array[idx]; |
| 293 | array[idx] = newObject; // replace oldObject with newObject |
| 294 | |
| 295 | NSMutableDictionary *dictionary = ...; |
| 296 | NSString *key = ...; |
| 297 | oldObject = dictionary[key]; |
| 298 | dictionary[key] = newObject; // replace oldObject with newObject |
| 299 | |
| 300 | The next section explains how subscripting expressions map to accessor |
| 301 | methods. |
| 302 | |
| 303 | Subscripting Methods |
| 304 | -------------------- |
| 305 | |
| 306 | Objective-C supports two kinds of subscript expressions: *array-style* |
| 307 | subscript expressions use integer typed subscripts; *dictionary-style* |
| 308 | subscript expressions use Objective-C object pointer typed subscripts. |
| 309 | Each type of subscript expression is mapped to a message send using a |
| 310 | predefined selector. The advantage of this design is flexibility: class |
| 311 | designers are free to introduce subscripting by declaring methods or by |
| 312 | adopting protocols. Moreover, because the method names are selected by |
| 313 | the type of the subscript, an object can be subscripted using both array |
| 314 | and dictionary styles. |
| 315 | |
| 316 | Array-Style Subscripting |
| 317 | ^^^^^^^^^^^^^^^^^^^^^^^^ |
| 318 | |
| 319 | When the subscript operand has an integral type, the expression is |
| 320 | rewritten to use one of two different selectors, depending on whether |
| 321 | the element is being read or written. When an expression reads an |
| 322 | element using an integral index, as in the following example: |
| 323 | |
| 324 | .. code-block:: objc |
| 325 | |
| 326 | NSUInteger idx = ...; |
| 327 | id value = object[idx]; |
| 328 | |
| 329 | it is translated into a call to ``objectAtIndexedSubscript:`` |
| 330 | |
| 331 | .. code-block:: objc |
| 332 | |
| 333 | id value = [object objectAtIndexedSubscript:idx]; |
| 334 | |
| 335 | When an expression writes an element using an integral index: |
| 336 | |
| 337 | .. code-block:: objc |
| 338 | |
| 339 | object[idx] = newValue; |
| 340 | |
| 341 | it is translated to a call to ``setObject:atIndexedSubscript:`` |
| 342 | |
| 343 | .. code-block:: objc |
| 344 | |
| 345 | [object setObject:newValue atIndexedSubscript:idx]; |
| 346 | |
| 347 | These message sends are then type-checked and performed just like |
| 348 | explicit message sends. The method used for objectAtIndexedSubscript: |
| 349 | must be declared with an argument of integral type and a return value of |
| 350 | some Objective-C object pointer type. The method used for |
| 351 | setObject:atIndexedSubscript: must be declared with its first argument |
| 352 | having some Objective-C pointer type and its second argument having |
| 353 | integral type. |
| 354 | |
| 355 | The meaning of indexes is left up to the declaring class. The compiler |
| 356 | will coerce the index to the appropriate argument type of the method it |
| 357 | uses for type-checking. For an instance of ``NSArray``, reading an |
| 358 | element using an index outside the range ``[0, array.count)`` will raise |
| 359 | an exception. For an instance of ``NSMutableArray``, assigning to an |
| 360 | element using an index within this range will replace that element, but |
| 361 | assigning to an element using an index outside this range will raise an |
| 362 | exception; no syntax is provided for inserting, appending, or removing |
| 363 | elements for mutable arrays. |
| 364 | |
| 365 | A class need not declare both methods in order to take advantage of this |
| 366 | language feature. For example, the class ``NSArray`` declares only |
| 367 | ``objectAtIndexedSubscript:``, so that assignments to elements will fail |
| 368 | to type-check; moreover, its subclass ``NSMutableArray`` declares |
| 369 | ``setObject:atIndexedSubscript:``. |
| 370 | |
| 371 | Dictionary-Style Subscripting |
| 372 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 373 | |
| 374 | When the subscript operand has an Objective-C object pointer type, the |
| 375 | expression is rewritten to use one of two different selectors, depending |
| 376 | on whether the element is being read from or written to. When an |
| 377 | expression reads an element using an Objective-C object pointer |
| 378 | subscript operand, as in the following example: |
| 379 | |
| 380 | .. code-block:: objc |
| 381 | |
| 382 | id key = ...; |
| 383 | id value = object[key]; |
| 384 | |
| 385 | it is translated into a call to the ``objectForKeyedSubscript:`` method: |
| 386 | |
| 387 | .. code-block:: objc |
| 388 | |
| 389 | id value = [object objectForKeyedSubscript:key]; |
| 390 | |
| 391 | When an expression writes an element using an Objective-C object pointer |
| 392 | subscript: |
| 393 | |
| 394 | .. code-block:: objc |
| 395 | |
| 396 | object[key] = newValue; |
| 397 | |
| 398 | it is translated to a call to ``setObject:forKeyedSubscript:`` |
| 399 | |
| 400 | .. code-block:: objc |
| 401 | |
| 402 | [object setObject:newValue forKeyedSubscript:key]; |
| 403 | |
| 404 | The behavior of ``setObject:forKeyedSubscript:`` is class-specific; but |
| 405 | in general it should replace an existing value if one is already |
| 406 | associated with a key, otherwise it should add a new value for the key. |
| 407 | No syntax is provided for removing elements from mutable dictionaries. |
| 408 | |
| 409 | Discussion |
| 410 | ---------- |
| 411 | |
| 412 | An Objective-C subscript expression occurs when the base operand of the |
| 413 | C subscript operator has an Objective-C object pointer type. Since this |
| 414 | potentially collides with pointer arithmetic on the value, these |
| 415 | expressions are only supported under the modern Objective-C runtime, |
| 416 | which categorically forbids such arithmetic. |
| 417 | |
| 418 | Currently, only subscripts of integral or Objective-C object pointer |
| 419 | type are supported. In C++, a class type can be used if it has a single |
| 420 | conversion function to an integral or Objective-C pointer type, in which |
| 421 | case that conversion is applied and analysis continues as appropriate. |
| 422 | Otherwise, the expression is ill-formed. |
| 423 | |
| 424 | An Objective-C object subscript expression is always an l-value. If the |
| 425 | expression appears on the left-hand side of a simple assignment operator |
| 426 | (=), the element is written as described below. If the expression |
| 427 | appears on the left-hand side of a compound assignment operator (e.g. |
| 428 | +=), the program is ill-formed, because the result of reading an element |
| 429 | is always an Objective-C object pointer and no binary operators are |
| 430 | legal on such pointers. If the expression appears in any other position, |
| 431 | the element is read as described below. It is an error to take the |
| 432 | address of a subscript expression, or (in C++) to bind a reference to |
| 433 | it. |
| 434 | |
| 435 | Programs can use object subscripting with Objective-C object pointers of |
| 436 | type ``id``. Normal dynamic message send rules apply; the compiler must |
| 437 | see *some* declaration of the subscripting methods, and will pick the |
| 438 | declaration seen first. |
| 439 | |
| 440 | Caveats |
| 441 | ======= |
| 442 | |
| 443 | Objects created using the literal or boxed expression syntax are not |
| 444 | guaranteed to be uniqued by the runtime, but nor are they guaranteed to |
| 445 | be newly-allocated. As such, the result of performing direct comparisons |
| 446 | against the location of an object literal (using ``==``, ``!=``, ``<``, |
| 447 | ``<=``, ``>``, or ``>=``) is not well-defined. This is usually a simple |
| 448 | mistake in code that intended to call the ``isEqual:`` method (or the |
| 449 | ``compare:`` method). |
| 450 | |
| 451 | This caveat applies to compile-time string literals as well. |
| 452 | Historically, string literals (using the ``@"..."`` syntax) have been |
| 453 | uniqued across translation units during linking. This is an |
| 454 | implementation detail of the compiler and should not be relied upon. If |
| 455 | you are using such code, please use global string constants instead |
| 456 | (``NSString * const MyConst = @"..."``) or use ``isEqual:``. |
| 457 | |
| 458 | Grammar Additions |
| 459 | ================= |
| 460 | |
| 461 | To support the new syntax described above, the Objective-C |
| 462 | ``@``-expression grammar has the following new productions: |
| 463 | |
| 464 | :: |
| 465 | |
| 466 | objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal) |
| 467 | ; |
| 468 | |
| 469 | object-literal : ('+' | '-')? numeric-constant |
| 470 | | character-constant |
| 471 | | boolean-constant |
| 472 | | array-literal |
| 473 | | dictionary-literal |
| 474 | ; |
| 475 | |
| 476 | boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */ |
| 477 | ; |
| 478 | |
| 479 | array-literal : '[' assignment-expression-list ']' |
| 480 | ; |
| 481 | |
| 482 | assignment-expression-list : assignment-expression (',' assignment-expression-list)? |
| 483 | | /* empty */ |
| 484 | ; |
| 485 | |
| 486 | dictionary-literal : '{' key-value-list '}' |
| 487 | ; |
| 488 | |
| 489 | key-value-list : key-value-pair (',' key-value-list)? |
| 490 | | /* empty */ |
| 491 | ; |
| 492 | |
| 493 | key-value-pair : assignment-expression ':' assignment-expression |
| 494 | ; |
| 495 | |
| 496 | Note: ``@true`` and ``@false`` are only supported in Objective-C++. |
| 497 | |
| 498 | Availability Checks |
| 499 | =================== |
| 500 | |
| 501 | Programs test for the new features by using clang's \_\_has\_feature |
| 502 | checks. Here are examples of their use: |
| 503 | |
| 504 | .. code-block:: objc |
| 505 | |
| 506 | #if __has_feature(objc_array_literals) |
| 507 | // new way. |
| 508 | NSArray *elements = @[ @"H", @"He", @"O", @"C" ]; |
| 509 | #else |
| 510 | // old way (equivalent). |
| 511 | id objects[] = { @"H", @"He", @"O", @"C" }; |
| 512 | NSArray *elements = [NSArray arrayWithObjects:objects count:4]; |
| 513 | #endif |
| 514 | |
| 515 | #if __has_feature(objc_dictionary_literals) |
| 516 | // new way. |
| 517 | NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 }; |
| 518 | #else |
| 519 | // old way (equivalent). |
| 520 | id keys[] = { @"H", @"He", @"O", @"C" }; |
| 521 | id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026], |
| 522 | [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] }; |
| 523 | NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4]; |
| 524 | #endif |
| 525 | |
| 526 | #if __has_feature(objc_subscripting) |
| 527 | NSUInteger i, count = elements.count; |
| 528 | for (i = 0; i < count; ++i) { |
| 529 | NSString *element = elements[i]; |
| 530 | NSNumber *mass = masses[element]; |
| 531 | NSLog(@"the mass of %@ is %@", element, mass); |
| 532 | } |
| 533 | #else |
| 534 | NSUInteger i, count = [elements count]; |
| 535 | for (i = 0; i < count; ++i) { |
| 536 | NSString *element = [elements objectAtIndex:i]; |
| 537 | NSNumber *mass = [masses objectForKey:element]; |
| 538 | NSLog(@"the mass of %@ is %@", element, mass); |
| 539 | } |
| 540 | #endif |
| 541 | |
| 542 | Code can use also ``__has_feature(objc_bool)`` to check for the |
| 543 | availability of numeric literals support. This checks for the new |
| 544 | ``__objc_yes / __objc_no`` keywords, which enable the use of |
| 545 | ``@YES / @NO`` literals. |
| 546 | |
| 547 | To check whether boxed expressions are supported, use |
| 548 | ``__has_feature(objc_boxed_expressions)`` feature macro. |