前言:
苹果在WWDC2012大会上介绍了大量Objective-C的新特性。在更新的XCode4.4版本中,这些新特性已经可以使用了。起因:Xcode 4.4附带有苹果LLVM编译器4.0,其中纳入了在Clang的前端版本3.1生效的改变。
(说明:Clang是开源C语言家族对于LLVM编译器的前端。Clang负责可以追溯到几年前的所有重要的语言特点,比如“构建与分析”,ARC,块,以及当通过GCC编译时近3倍的性能提升)
参考:http://clang.llvm.org/docs/ObjectiveCLiterals.html
============NSNumber Literals(字面)============
NSNumber介绍:The framework class NSNumber is used to wrap scalar values inside objects: signed and unsigned integers (char, short, int, long, long long),floating point numbers (float, double), and boolean values (BOOL, C++ bool). Scalar values wrapped in objects are also known as boxed values.
规则rules for NSNumber literals:any character, numeric or boolean literal prefixed with the '@' character will evaluate to a pointer to an NSNumber object initialized with that value. C’s type suffixes may be used to control the size of numeric literals. 例,
// character literals. NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z'] // integral literals. NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42] NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U] NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L] NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL] // floating point literals. NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F] NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535] // BOOL literals. NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES] NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO] #ifdef __cplusplus NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true] NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false] #endif说明:
--1.NSNumber literals only support literal scalar values after the '@'. Consequently,@INT_MAXworks, but @INT_MIN does not,具体查下下文定义。另The definition of INT_MIN is not a simple literal, but a parenthesized括号 expression. Parenthesized expressions are supported using the boxed expression syntax,详细查看下文。
#define INT_MAX 2147483647 /* max value for an int */ #define INT_MIN (-2147483647-1) /* min value for an int
即:@后面直接接字面常量可以,但是如果接变量或者表达式就不行,如果要使用Object Literals,就用Boxed Expressions。
NSNumber *num1 = @234; NSNumber *num0 = @(a); // NSNumber *num2 = @a; 错误写法 NSNumber *num4 = @(3-4); // NSNumber *num3 = @3-4; 错误写法
-2.Because NSNumber does not currently support wrapping long double values, e.g. @123.23L will be rejected by the compiler.
--3.Previously, the BOOL type was simply a typedef for signed char, and YES and NO were macros that expand to(BOOL)1 and(BOOL)0 respectively. To support @YES and @NO expressions, these macros are now defined using new language keywords in <objc/objc.h>:
#if __has_feature(objc_bool) #define YES __objc_yes #define NO __objc_no #else #define YES ((BOOL)1) #define NO ((BOOL)0) #endifThe compiler implicitly converts __objc_yes and __objc_no to (BOOL)1 and (BOOL)0. The keywords are used to disambiguate消除歧义 BOOL and integer literals.
============Boxed Expressions============
syntax:@( <expression> )
Expressions of scalar (numeric, enumerated, BOOL) and C string pointer types are supported:
// numbers. NSNumber *smallestInt = @(-INT_MAX - 1); // [NSNumber numberWithInt:(-INT_MAX - 1)] NSNumber *piOverTwo = @(M_PI / 2); // [NSNumber numberWithDouble:(M_PI / 2)] // enumerated types. typedef enum { Red, Green, Blue } Color; NSNumber *favoriteColor = @(Green); // [NSNumber numberWithInt:((int)Green)] // strings. NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))]------------Boxed Enums------------
Cocoa frameworks frequently define constant values using enums. Although enum values are integral, they may not be used directly as boxed literals(this avoids conflicts with future '@'-prefixed Objective-C keywords). Instead, an enum value must be placed inside a boxed expression. The following example demonstrates configuring an AVAudioRecorder using a dictionary that contains a boxed enumeration value:
enum { AVAudioQualityMin = 0, AVAudioQualityLow = 0x20, AVAudioQualityMedium = 0x40, AVAudioQualityHigh = 0x60, AVAudioQualityMax = 0x7F }; - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL { NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) }; return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL]; }The expression @(AVAudioQualityMax) converts AVAudioQualityMax to an integer type, and boxes the value accordingly. If the enum has a fixed underlying type as in
typedef enum : unsigned char { Red, Green, Blue } Color;then the fixed underlying type will be used to select the correct NSNumber creation method.
typedef enum : unsigned char { Red, Green, Blue } Color; Color col = Red; NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]------------Boxed C Strings-----------
// Partition command line arguments into positional and option arguments. NSMutableArray *args = [NSMutableArray new]; NSMutableDictionary *options = [NSMutableDictionary new]; while (--argc) { const char *arg = *++argv; if (strncmp(arg, "--", 2) == 0) { options[@(arg + 2)] = @(*++argv); // --key value } else { [args addObject:@(arg)]; // positional argument } }As with all C pointers, character pointer expressions can involve arbitrary pointer arithmetic, therefore programmers must ensure that the character data is valid. Passing NULL as the character pointer will raise an exception at runtime. When possible, the compiler will reject NULL character pointers used in boxed expressions.
// Immutable array: NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ]; // Immutable dictionary NSDictionary *dictionary = @{ @"name" : NSUserName(), @"date" : [NSDate date], @"processInfo" : [NSProcessInfo processInfo] };说明:
--1.Neither keys nor values can have the value nil in containers. If the compiler can prove that a key or value is nil at compile time, then awarning will be emitted. Otherwise, a runtime error will occur.集合中不能有nil,如果编译时能检测出来会有警告;否则运行的时候会崩溃。
--2.Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to +[NSArray arrayWithObjects:count:], which validates thatall objects are non-nil. The variadic form, +[NSArray arrayWithObjects:]uses nil as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with +[NSDictionary dictionaryWithObjects:forKeys:count:] which validates all objects and keys, unlike +[NSDictionary dictionaryWithObjectsAndKeys:] which also uses anil parameter as an argument list terminator. 实际对应的方法。
============Object Subscripting下标============
数组和字典now be used with C’s subscripting operator。
NSMutableArray *array = ...; NSUInteger idx = ...; id newObject = ...; id oldObject = array[idx]; array[idx] = newObject; // replace oldObject with newObject NSMutableDictionary *dictionary = ...; NSString *key = ...; oldObject = dictionary[key]; dictionary[key] = newObject; // replace oldObject with newObject------------ Subscripting Methods []对应的方法 ----------
Objective-C支持俩种subscript expressions:array-style subscript expressions 和 dictionary-style subscript expressions。
前者使用integer typed subscripts,后者使用Objective-C object pointer typed subscripts.The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.
Array-Style Subscripting
// depending on whether the element is being read or written id value = object[idx]; // 相当id value = [object objectAtIndexedSubscript:idx]; object[idx] = newValue; // 相当[object setObject:newValue atIndexedSubscript:idx];
These message sends are then type-checked and performed just like explicit message sends。
Dictionary-Style Subscripting// depending on whether the element is being read from or written to id value = object[key]; // 相当id value = [object objectForKeyedSubscript:key]; object[key] = newValue; // 相当[object setObject:newValue forKeyedSubscript:key];The behavior of setObject:forKeyedSubscript: is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elementsfrom mutable dictionaries。
备注:
1.如果Objective-C是C的超集,对象下标索引如何重载[]C运算符?现代的Objective-C运行禁止对象的指针运算,使得这个语法转换成为可能。
2.自定义下标方法:
自定义索引下标:为你的类增加自定义索引下标,你只需要声明和实现下列方法
- (id)objectAtIndexedSubscript:(NSUInteger)idx; - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;自定义键位下标:你也可以通过声明和实现以下方法增加自定义键位下标到你的类:
- (id)objectForKeyedSubscript:(id <NSCopying>)key; - (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
========================================
============Availability Checks============
using clang’s __has_feature checks
#if __has_feature(objc_array_literals) // new way. NSArray *elements = @[ @"H", @"He", @"O", @"C" ]; #else // old way (equivalent). id objects[] = { @"H", @"He", @"O", @"C" }; NSArray *elements = [NSArray arrayWithObjects:objects count:4]; #endif #if __has_feature(objc_dictionary_literals) // new way. NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 }; #else // old way (equivalent). id keys[] = { @"H", @"He", @"O", @"C" }; id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026], [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] }; NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4]; #endif #if __has_feature(objc_subscripting) NSUInteger i, count = elements.count; for (i = 0; i < count; ++i) { NSString *element = elements[i]; NSNumber *mass = masses[element]; NSLog(@"the mass of %@ is %@", element, mass); } #else NSUInteger i, count = [elements count]; for (i = 0; i < count; ++i) { NSString *element = [elements objectAtIndex:i]; NSNumber *mass = [masses objectForKey:element]; NSLog(@"the mass of %@ is %@", element, mass); } #endif