这么多年过去了,Objective—C不断的成长和进化。虽然核心思想和实践保持不变,可是语言仍是产生了标志性的改变和提升。这些现代化的提升体如今类型安全、内存管理、性能和Objective—C的其余方面,这些让咱们更加容易的编写正确的代码。express
使用instancetype做为关键字的函数返回一个类的实例,这个函数方法里面包含alloc、init和这个类的工厂方法。xcode
使用instancetype代替id会提升代码的类型安全。例如安全
@interface MyObject : NSObject + (instancetype)factoryMethodA; + (id)factoryMethodB; @end @implementation MyObject + (instancetype)factoryMethodA { return [[[self class] alloc] init]; } + (id)factoryMethodB { return [[[self class] alloc] init]; } @end void doSomething() { NSUInteger x, y; x = [[MyObject factoryMethodA] count]; // Return type of +factoryMethodA is taken to be "MyObject *" y = [[MyObject factoryMethodB] count]; // Return type of +factoryMethodB is "id" }
由于用instancetype做为返回类型的函数+factoryMethodA,这个消息的类型表示的是Myobject *。由于Myobject类没有-count方法。编译器会再 x 行报出警告:编辑器
main.m: ’MyObject’ may not respond to ‘count’
然而,使用id类型的话,表示的是任何一个类型,因此里面可能会包含有-count,编译器就不会报出错误提示。函数
在子类中,为了确保instancetype的工厂方法有正确的子类行为,当分配一个类的时候,要用[self class]代替直接使用类名。工具
例如在上面的类的子类以下:性能
@interface MyObjectSubclass : MyObject @end void doSomethingElse() { NSString *aString = [MyObjectSubclass factoryMethodA]; }
编译器会给出如下错误提示:atom
main.m: Incompatible pointer types initializing ’NSString *’ with an expression of type ’MyObjectSubclass *’
在你的代码中,用instancetype替代已经存在的id。有表明性的是init方法和类工厂方法。编辑器只会替咱们自动把以alloc、init、new开头的方法和返回值为id的方法转换成返回instancetype的方法,可是编辑器不会覆盖其余的方法。Objective-C 中约定明确的为全部方法写上instancetype。code
注意:你只须要在返回值的地方用instancetype替换id,er'bu'而不是把全部的id都用instancetype替换。instancetype只能做为函数声明的返回值。这是和id的不一样点。对象
例如:
@interface MyObject - (id)myFactoryMethod; @end
应该变成
@interface MyObject - (instancetype)myFactoryMethod; @end
还有一种方法,你能够在xcode中使用Objective-C的转换器自动改变你的代码,方法是下面的用xcode重构代码
xcode提供现代Objective-C转换工具,在开发工程中能够辅助咱们,它能够识别并应用现代化工具转换代码,但它并不能解释代码的意思。例如:它不会知道你的-toggle方法会影响你的对象的状态,而且它可能会错误的认为这个行为是一个属性。因此凡是自动转换的代码都要手动进行审查和确认。
它会帮咱们作这些事情:
除了这些,它还会更改你的代码的地方以下:
使用这种模式,选择Edit > Refactor > Convert to Modern Objective-C Syntax.
使用@property声明属性比使用实例变量带来的好处是:
属性的名字有一套命名规则:属性的getter方法名就是属性的名字自己(例如:属性date的getter方法就是date),属性的setter方法就是在属性名前面加上set前缀(例如:属性date的setter方法就是setDate)。Boolean属性的getter方法以is开头
@property (readonly, getter=isBlue) BOOL blue;
这样作就能像下面这样使用了:
if (color.blue) { } if (color.isBlue) { } if ([color isBlue]) { }
使用NS_ENUM 和 NS_OPTIONS宏定义枚举,能够明确的指定你的宏的类型和大小,,除此以外,这个语法在老的编辑器中也能被识别。
使用NS_ENUM宏定义一组互斥的枚举值:
typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2, UITableViewCellStyleSubtitle };
NS_ENUM帮助定义名字和类型的列举,这里名字是UITableViewCellStyle,类型是NSInteger。这中类型的枚举应该是NSInteger。
使用NS_OPTIONS定义一个能够组合的值:
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 };
这种类型的枚举一般使用NSUInteger。