前幾日被人提問,Foundation庫下的NSString可以被繼承嗎? 一下子把我問蒙圈了,從來沒有用過呀! 後來自己一用代碼一試。
寫了一個繼承於NSString 的類。然後在VC中去初始化。
看來了一切是那樣的風平浪靜。但是一運行的時候,浪浪的事發生了
直接崩潰了,說找不到這個抽象的方法。但是不應該呀,我繼承了NSString類就應該可以用它裏面的方法呀。
官方文檔有介紹類簇可以看一下寫的很詳細:
[https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html]
下面我就把自己的理解寫下來,類簇就是把一組有共同特性的子類都繼承說一個父類,當我們在需要各個子類的時候,我們就需要去操作父類就可以,運用抽象工廠模式,父類會根據你的需求返回給你相應的子類。比如
NSNumber *aChar = [NSNumber numberWithChar:’a’];
NSNumber *anInt = [NSNumber numberWithInt:1];
NSNumber *aFloat = [NSNumber numberWithFloat:1.0];
NSNumber *aDouble = [NSNumber numberWithDouble:1.0];
我們只需要操作NSNumber就可以得到相應的char,int ,flat,double類性的對象。
但爲什麼會繼承這樣類會崩潰呢?接下來看看另一代碼
發現+ alloc後並非生成了我們期望的類實例,而是一個NSPlaceholderString的中間對象,後面的- init或- initWithXXXXX消息都是發送給這個中間對象,再由它做工廠,生成真的對象分別是這裏的NSCFConstantString和NSCFString_類
於是順着思路猜實現,NSPlaceholderString必定用某種方式存儲了它是由誰alloc出來的這個信息,才能在init的時候知道要創建的是可變字符串還是不可變字符串。
這裏還有個現象:
跟蹤[LBString alloc]返回的對象類型爲LBString類,
跟蹤[NSString alloc]返回的對象類型爲NSPlaceholderString,而不是NSString類。。
推斷是 NSString alloc時有個中間層,就是我們上面看到的NSPlaceholderString,alloc的對象先統一爲這個類對象之後,在後面調用 NSPlaceholderString的類方法時,比如initWithFormat:才返回具體的類,即在NSPlaceholderString這一層做個“代理工廠”,根據調用的不同init方法再返回具體的類,比如 NSCFString。
那麼爲什麼我們自己的類調用alloc時,就不返回NSPlaceholderString這個類對象了呢?關鍵就在於NSString alloc方法的實現。NSString的alloc方法實現可以猜測一下:
@class NSPlaceholderString;
@interface NSString:(NSObject)
+ (id) alloc;
@ end
@implementation NSString
+(id) alloc {
if ([self isEquals:[NSString class]]) {
return [NSPlaceholderString alloc];
}
else
return [super alloc];
}
@end
@interface NSPlaceholderString:(NSString)
@end
關鍵就在於alloc的實現,可以發現,當只用NSString調用alloc的時候,由於self == [NSString class],所以這時返回的是NSPlaceholderString的類對象;而使用其他類(比如派生類)調用alloc時,返回的是super的 alloc,這裏也就是[NSObject alloc],而NSObject的alloc方法返回的是調用類的類對象,所以在我們用我們自己的LBString就是LBString類的類對象了所以沒有NSString 的一些方法了。