Objective-C 的輕量泛型

Lightweight Generics

Lightweight Generics 輕量級泛型,輕量是因為這是個純編譯器的語法支持(llvm 7.0),和 Nullability 一樣,沒有借助任何 objc runtime 的升級,也就是說,這個新語法在 Xcode 7 上可以使用且完全向下兼容(更低的 iOS 版本)

帶泛型的容器

這無疑是本次最重大的改進(jìn),有了泛型后終于可以指定容器類中對象的類型了:

NSArray<NSString *> *strings = @[@"sun", @"yuan"];
NSDictionary<NSString *, NSNumber *> *mapping = @{@"a": @1, @"b": @2};

返回值的 id 被替換成具體的類型后,令人感動的代碼提示也出來了:

image

假如向泛型容器中加入錯誤的對象,編譯器會不開心的:

image

系統(tǒng)中常用的一系列容器類型都增加了泛型支持,甚至連 NSEnumerator 都支持了,這是非常 Nice 的改進(jìn)。和 Nullability 一樣,我認(rèn)為最大的意義還是豐富了接口描述信息,對比下面兩種寫法:

@property (readonly) NSArray *imageURLs;
@property (readonly) NSArray<NSURL *> *imageURLs;

不用多想就清楚下面的數(shù)組中存的是什么,避免了 NSString 和 NSURL 的混亂。

自定義泛型類

比起使用系統(tǒng)的泛型容器,更好玩的是自定義一個泛型類,目前這里還沒什么文檔,但攔不住我們寫測試代碼,假設(shè)我們要自定義一個 Stack 容器類:

@interface Stack<ObjectType> : NSObject
- (void)pushObject:(ObjectType)object;
- (ObjectType)popObject;
@property (nonatomic, readonly) NSArray<ObjectType> *allObjects;
@end

這個 ObjectType 是傳入類型的 placeholder,它只能在 @interface 上定義(類聲明、類擴(kuò)展、Category),如果你喜歡用 T 表示也 ok,這個類型在 @interface 和 @end 區(qū)間的作用域有效,可以把它作為入?yún)ⅰ⒊鰠ⅰ⑸踔羶?nèi)部 NSArray 屬性的泛型類型,應(yīng)該說一切都是符合預(yù)期的。我們還可以給 ObjectType 增加類型限制,比如:

// 只接受 NSNumber * 的泛型
@interface Stack<ObjectType: NSNumber *> : NSObject
// 只接受滿足 NSCopying 協(xié)議的泛型
@interface Stack<ObjectType: id<NSCopying>> : NSObject

若什么都不加,表示接受任意類型 ( id );當(dāng)類型不滿足時編譯器將產(chǎn)生 error。
實例化一個 Stack,一切工作正常:

image

對于多參數(shù)的泛型,用逗號隔開,其他都一樣,可以參考 NSDictionary 的頭文件。

協(xié)變性和逆變性

當(dāng)類支持泛型后,它們的 Type 發(fā)生了變化,比如下面三個對象看上去都是 Stack,但實際上屬于三個 Type:

Stack *stack; // Stack *
Stack<NSString *> *stringStack; // Stack<NSString *>
Stack<NSMutableString *> *mutableStringStack; // Stack<NSMutableString *>

當(dāng)其中兩種類型做類型轉(zhuǎn)化時,編譯器需要知道哪些轉(zhuǎn)化是允許的,哪些是禁止的,比如,默認(rèn)情況下:

image

我們可以看到,不指定泛型類型的 Stack 可以和任意泛型類型轉(zhuǎn)化,但指定了泛型類型后,兩個不同類型間是不可以強(qiáng)轉(zhuǎn)的,假如你希望主動控制轉(zhuǎn)化關(guān)系,就需要使用泛型的協(xié)變性逆變性修飾符了:

__covariant - 協(xié)變性,子類型可以強(qiáng)轉(zhuǎn)到父類型(里氏替換原則)
__contravariant - 逆變性,父類型可以強(qiáng)轉(zhuǎn)到子類型(WTF?)

協(xié)變:

@interface Stack<__covariant ObjectType> : NSObject

效果:

image

逆變:

@interface Stack<__contravariant ObjectType> : NSObject

效果:

image

協(xié)變是非常好理解的,像 NSArray 的泛型就用了協(xié)變的修飾符,而逆變我還沒有想到有什么實際的使用場景。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容