為什么要使用泛型
在使用NSArray, NSSet, NSDictionary 中都有使用泛型.
先來看一段沒有使用泛型的的代碼
NSMutableArray *arr = [NSMutableArray array];
[arr addObject:@1];
[arr addObject:@"wang"];
[arr addObject:@{}];
在這段代碼中可以給數組中添加任意對象, 但是實際情況中我們希望使用數組用來保存同一種類型的變量.
實際情況中,我們可能希望使用數組保存一組NSString,但是我們操作失誤在數組中添加的一個NSNumber使用上面的代碼,在編譯階段,Xcode并不會提示錯誤或給出警告,但是在實際使用中,我們認為這個數組中都是NSString類型的變量,導致對NSNumber使用NSString的方法導致程序crash,顯然這樣的程序是不健壯的.
還好使用泛型可以解決這樣的問題,代碼如下
使用泛型指定數組中的類型為NSString,當我們在數組中添加其他類型時,就會出現提示.
在我們沒有指定泛型時,提示顯示可以添加id類型
當我指定泛型時,提示的是在聲明過程中與泛型對應的類型.
使用集合時用泛型聲明可以幫助你檢查集合中的類型,還能提示集合中應存放的類型.
如何使用泛型
我們先看一下NSArray中泛型的使用
通過觀察發現,泛型起到的作用就是占位符的作用.
聲明一個數組的指定泛型為NSString *, ObjectType就是一個占位符, 在接口中任何使用ObjectType泛型占位符的時候都會替換為NSString *
類型.
了解了系統泛型使用方法然后自己創建一個ClassStack
使用泛型.
@interface Stack <__covariant T> : NSObject
- (void)push:(T)obj;
- (T)pop;
@end
在聲明.h 我們都可以使用泛型T
作為占位符.
在類擴展和分類中并不能使用T
泛型.
如果要做分類和類擴展中使用泛型需要重新指定.
在實現中是不能使用泛型的.
限制泛型
通常我們在使用泛型時可以代替任意id類型,但有時我們使用泛型時,希望對泛型進行限制,我們希望泛型為UIView類簇中的類型.
很顯然這并不是我們希望看到了,所以我們可以對泛型進行限制
@interface Stack <__covariant T : UIView *> : NSObject
- (void)push:(T)obj;
- (T)pop;
@end
使用上面聲明方法可以解決問題.
同時也可以限制泛型遵守指定的協議
@interface Stack <__covariant T : id<protocol>> : NSObject
- (void)push:(T)obj;
- (T)pop;
@end
協變 逆變
在上面我們開到了關鍵字__covariant
,下面就來看看這個關鍵字的作用
__covariant
:協變, 子類轉父類 :也就是將子類的指針賦值給父類(多態的延伸)
__contravariant
:逆變 父類轉子類:也就是將父類的指針賦值給子類(暫時沒有想到有什么作用,如果有哪位大佬知道歡迎指點一二).
在這里我們創建兩個類Animal
和他的子類Dog
.
//測試代碼
Stack <Dog *> *stack1 = [Stack new];
Stack <Animal *> *stack2 = [Stack new];
stack1 = stack2;
stack2 = stack1;
接下來我們分別來看看協變和逆變的特性.
// 逆變 父類指向子類
@interface Stack <__contravariant T : Animal *> : NSObject
// 協變 子類指向父類
@interface Stack <__covariant T : Animal *> : NSObject