這麼多年過去了,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。