1. 什麼是 instancetype
instancetype 是 clang 3.5 開始,clang 提供的一個關鍵字,表示某個方法傳回的未知類型的 Objective-C 對象。我們都知道未知類型的的對象可以用 id 關鍵字表示,那為什麼還會再有一個 instancetype 呢?
2. 關聯傳回類型(related result types)
根據 Cocoa 的命名規則,滿足下述規則:
- 類方法中,以
或alloc
開頭new
- 執行個體方法中,以
,autorelease
,init
或retain
開頭self
的方法會傳回一個方法所在類的類型的對象,這些方法就被稱為是 關聯傳回類型 的方法。換句話說,這些方法的傳回結果以方法所在的類為類型。比如:
@interface NSObject
+ (id)alloc;
- (id)init;
@end
@interface NSArray : NSObject
@end
當我們使用如下方式初始化
NSArray
時:
NSArray *array = [[NSArray alloc] init];
按照 Cocoa 的命名規則,語句
[NSArray alloc]
的類型就是
NSArray*
。因為
alloc
的傳回類型屬于關聯傳回類型。同樣,
[[NSArray alloc] init]
的傳回結果也是
NSArray*
。
3. instancetype 作用
3.1 作用
如果一個不是關聯傳回類型的方法,如下:
@interface NSArray
+ (id)constructAnArray;
@end
當我們使用如下方式初始化 NSArray 時:
根據 Cocoa 的方法命名規範,得到的傳回類型就和方法聲明的傳回類型一樣,是
id
。但是如果使用
instancetype
作為傳回類型,如下:
@interface NSArray
+ (instancetype)constructAnArray;
@end
當使用相同方式初始化 NSArray 時:
得到的傳回類型和方法所在類的類型相同,是
NSArray*
!
總結一下,
instancetype
的作用,就是使那些非關聯傳回類型的方法傳回所在類的類型!
3.2 好處
能夠确定對象的類型,能夠幫助編譯器更好的為我們定位代碼書寫問題,比如:
[[[NSArray alloc] init] mediaPlaybackAllowsAirPlay]; // "No visible @interface for `NSArray` declares the selector `mediaPlaybackAllowsAirPlay`"
[[NSArray array] mediaPlaybackAllowsAirPlay]; // (No error)
上例中第一行代碼,由于
[[NSArray alloc] init]
的結果是
NSArray*
,這樣編譯器就能夠根據傳回的資料類型檢測出
NSArray
是否實作
mediaPlaybackAllowsAirPlay
方法。有利于開發者在編譯階段發現錯誤。
第二行代碼,由于
array
不屬于關聯傳回類型方法,
[NSArray array]
傳回的是
id
類型,編譯器不知道
id
類型的對象是否實作了
mediaPlaybackAllowsAirPlay
方法,也就不能夠替開發者及時發現錯誤。
4. instancetype 和 id 的異同
- 相同點
都可以作為方法的傳回類型。
- 不同點
-
可以傳回和方法所在類相同類型的對象,instancetype
隻能傳回未知類型的對象;id
-
隻能作為傳回值,不能像instancetype
那樣作為參數,比如下面的寫法:id
-
//err,expected a type
- (void)setValue:(instancetype)value
{
//do something
}
就是錯的,應該寫成:
- (void)setValue:(id)value
{
//do something
}
原文出處: Objective-C中的instancetype和id關鍵字
英文原文連結:
1. http://clang.llvm.org/docs/LanguageExtensions.html#objective-c-features
2. http://nshipster.com/instancetype/