前言
四年前Clang添加了關(guān)鍵字instancetype,目的在于取代-alloc和-init等方法的返回類型id,那么使用instancetype到底比id好在哪里?
instancetype宣言
不管何時,只要一個class要返回它相同的類實(shí)例,使用instancetype都是更加合適的。
我們知道,當(dāng)調(diào)用類中(或者子類)的-alloc、-init或者class factory(+)方法,使用instancetype關(guān)鍵字會返回它的類實(shí)例。在這種情況下用instancetype而不是id有100個好處。
蘋果也這樣說:
In your code, replace occurrences of id as a return value with instancetype where appropriate. This is typically the case for init methods and class factory methods. Even though the compiler automatically converts methods that begin with “alloc,” “init,” or “new” and have a return type of id to return instancetype, it doesn’t convert other methods. Objective-C convention is to write instancetype explicitly for all methods.
更加有力的證據(jù):Adopting Modern Objective-C
為什么?
首先你可能需要知道編譯器會做什么
@interface Foo:NSObject
- (id)initWithBar:(NSInteger)bar; // initializer
+ (id)fooWithBar:(NSInteger)bar; // convenience constructor
@end
對于convenience constructor,你必須要使用instancetype,因?yàn)榫幾g器不會把id自動轉(zhuǎn)換成instancetype。
而對于initializer,當(dāng)你的代碼是這樣的:
- (id)initWithBar:(NSInteger)bar; // initializer
ARC下,編譯器會把它變成這樣:
- (instancetype)initWithBar:(NSInteger)bar; // initializer
這也是為什么有人告訴你用instancetype是沒有必要的,但是我建議你使用instancetype,原因有三:
- 明確性:你的代碼含義明確,絕不會做其他事。
- 模式化:你建立了一個良好的習(xí)慣,這確實(shí)是很重要的。
- 一致性:讓你的代碼更一致,并且增加可讀性。
1.明確性
在-init方法中返回instancetype確實(shí)是沒有太多的好處,這是因?yàn)榫幾g器會自動把id轉(zhuǎn)換成instancetype。
這對于編譯器來講是等價的:
- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;
但是至少這在你眼中是不同的。
2.模式化
雖然對init或者其他方法,返回id和instancetype沒什么不同,但是在convenient constructor(+)方法中他們是有區(qū)別的:
+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
你必須要用第二條才能保證你每次運(yùn)行的結(jié)果正確,為什么?
考慮這樣的情況:
然后我們這樣調(diào)用:
發(fā)現(xiàn)x出現(xiàn)編譯警告,因?yàn)槲覀兊?factoryMethodA返回的是instancetype,它表示的是MyObject,因?yàn)镸yObject沒有-count*方法,所以出現(xiàn)了編譯警告。
然而,因?yàn)槲覀兊?factoryMethodB返回的是id,編譯器沒有在y行給警告,因?yàn)镺bjc語言動態(tài)類型和動態(tài)綁定的特性,id可能是任何class,又因?yàn)?strong>-count方法可能于存在某個類的某個地方,因此對于編譯器而言,+factoryMethodB方法返回的東西是可能實(shí)現(xiàn)-count方法的。
3.一致性
在init中可以返回id,因此你可能會這樣寫:
- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
但是如果你使用instancetype,結(jié)果會是這樣:
- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
這樣看起來更加一致并且可讀性更高。他們返回同樣的東西,但是后者看起來更明顯,不是嗎?
結(jié)論
當(dāng)要返回id類型的時候,你應(yīng)該思考它是否會返回一個類的實(shí)例,如果是,請使用instancetype。
參考鏈接:
Done
作者 @biggergao
2016年05月18日