WWDC 2012 Session笔记——405 Modern Objective-C
转载有道理!转载自 这篇文章
2007年的时候,Objective-C在TIOBE编程语言排名里还排在可怜的第45位,而随着移动互联网的迅速发展和iPhone,iPad等iOS设备的广阔市场前景,Objective-C也迅速崛起,走进了开发者的视野。在最近的TIOBE排名中,Objective-C达到了惊人的第4名,可以说已经成为当今世界上一门非常重要的编程语言。 而Objective-C现在主要是由Apple在负责维护了。一直以来Apple为了适应开发的发展需要,不断在完善OC以及相应的cocoa库,2.0中引入的property,随着iOS4引入的block,以及去年引入的ARC,都受到了绝大部分开发者的欢迎。几乎每年都有重大特性的加入,这不是每种语言都能做到的,更况且这些特性都为大家带来了众多的便利。 今年WWDC也不例外,OC和LLVM将得到重大的改进。本文将对这些改进进行一个简单整理和评述。
方法顺序
@interface SongPlayer : NSObject - (void)playSong:(Song *)song; @end @implementation SongPlayer - (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; ... } - (void)startAudio:(NSError **)error { ... } @end
在早一些的编译环境中,上面的代码会在[self startAudio:&error]处出现一个实例方法未找到的警告。由于编译顺序,编译器无法得知在-playSong:方法之后还有一个-startAudio:,因此给出警告。以前的解决方案有两种:要么将-startAudio:的实现移到-playSong:的上方,要么在类别中声明-startAudio:(顺便说一句..把-startAudio:直接拿到.h文件中是完全错误的做法,因为这个方法不应该是public的)。前者破坏.m文件的结构打乱了方法排列的顺序,导致以后维护麻烦;后者要写额外的不必要代码,使.m文件变长。其实两种方法都不是很好的解决方案。 现在不需要再头疼这个问题了,LLVM中加入了新特性,现在直接使用上面的代码,不需要做额外处理也可以避免警告了。新编译器改变了以往顺序编译的行为,改为先对方法申明进行扫描,然后在对方法具体实现进行编译。这样,在同一实现文件中,无论方法写在哪里,编译器都可以在对方法实现进行编译前知道所有方法的名称,从而避免了警告。
枚举改进
typedef enum NSNumberFormatterStyle : NSUInteger { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle } NSNumberFormatterStyle;
在列出枚举列表的同时绑定了枚举类型为NSUInteger,相比起以前的直接枚举和先枚举再绑定类型好处是方便编译器给出更准确的警告。个人觉得对于一般开发者用处并不是特别大,因为往往并不会涉及到很复杂的枚举,用以前的枚举申明方法也不至于就搞混。所以习惯用哪种枚举方式还是接着用就好了..不过如果有条件或者还没有形成自己的习惯或者要开新工程的话,还是尝试一下这种新方法比较好,因为相对来说要严格一些。
属性自动绑定
- 除非开发者在实现文件中提供getter或setter,否则将自动生成
- 除非开发者同时提供getter和setter,否则将自动生成实例变量
- 只要写了synthesis,无论有没有跟实例变量名,都将生成实例变量
- dynamic优先级高于synthesis
- [NSNumber numberWithChar:‘X’] 简写为 @‘X’;
- [NSNumber numberWithInt:12345] 简写为 @12345
- [NSNumber numberWithUnsignedLong:12345ul] 简写为 @12345ul
- [NSNumber numberWithLongLong:12345ll] 简写为 @12345ll
- [NSNumber numberWithFloat:123.45f] 简写为 @123.45f
- [NSNumber numberWithDouble:123.45] 简写为 @123.45
- [NSNumber numberWithBool:YES] 简写为 @YES
- [NSArray array] 简写为 @[]
- [NSArray arrayWithObject:a] 简写为 @[ a ]
- [NSArray arrayWithObjects:a, b, c, nil] 简写为 @[ a, b, c ]
// compiler generates: id objects[] = { a, b, c }; NSUInteger count = sizeof(objects)/ sizeof(id); array = [NSArray arrayWithObjects:objects count:count];
- [NSDictionary dictionary] 简写为 @{}
- [NSDictionary dictionaryWithObject:o1 forKey:k1] 简写为 @{ k1 : o1 }
- [NSDictionary dictionaryWithObjectsAndKeys:o1, k1, o2, k2, o3, k3, nil] 简写为 @{ k1 : o1, k2 : o2, k3 : o3 }
// compiler generates: id objects[] = { o1, o2, o3 }; id keys[] = { k1, k2, k3 }; NSUInteger count = sizeof(objects) / sizeof(id); dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];
NSMutableArray *mutablePlanets = [@[ @\\"Mercury\\", @\\"Venus\\", @\\"Earth\\", @\\"Mars\\", @\\"Jupiter\\", @\\"Saturn\\", @\\"Uranus\\", @\\"Neptune\\" ] mutableCopy];
另外,对于标记为static的数组(没有static的字典..哈希和排序是在编译时完成的而且cocoa框架的key也不是常数),不能使用简写为其赋值(其实原来的传统写法也不行)。解决方法是在类方法+ (void)initialize中对static进行赋值,比如:
static NSArray *thePlanets; + (void)initialize { if (self == [MyClass class]) { thePlanets = @[ @\\"Mercury\\", @\\"Venus\\", @\\"Earth\\", @\\"Mars\\", @\\"Jupiter\\", @\\"Saturn\\", @\\"Uranus\\", @\\"Neptune\\" ]; } }
- [array objectAtIndex:idx] 简写为 array[idx];
- [array replaceObjectAtIndex:idx withObject:newObj] 简写为 array[idx] = newObj
- [dic objectForKey:key] 简写为 dic[key]
- [dic setObject:object forKey:key] 简写为 dic[key] = newObject
- (elementType)objectAtIndexedSubscript:(indexType)idx; - (void)setObject:(elementType)object atIndexedSubscript:(indexType)idx;
对于类似字典的结构:
- (elementType)objectForKeyedSubscript:(keyType)key; - (void)setObject:(elementType)object forKeyedSubscript:(keyType)key;