為什么要使用泛型
在使用NSArray, NSSet, NSDictionary 中都有使用泛型.
先來看一段沒有使用泛型的的代碼
NSMutableArray *arr = [NSMutableArray array];
[arr addObject:@1];
[arr addObject:@"wang"];
[arr addObject:@{}];
在這段代碼中可以給數(shù)組中添加任意對象, 但是實際情況中我們希望使用數(shù)組用來保存同一種類型的變量.
實際情況中,我們可能希望使用數(shù)組保存一組NSString,但是我們操作失誤在數(shù)組中添加的一個NSNumber使用上面的代碼,在編譯階段,Xcode并不會提示錯誤或給出警告,但是在實際使用中,我們認(rèn)為這個數(shù)組中都是NSString類型的變量,導(dǎo)致對NSNumber使用NSString的方法導(dǎo)致程序crash,顯然這樣的程序是不健壯的.
還好使用泛型可以解決這樣的問題,代碼如下

使用泛型指定數(shù)組中的類型為NSString,當(dāng)我們在數(shù)組中添加其他類型時,就會出現(xiàn)提示.


在我們沒有指定泛型時,提示顯示可以添加id類型
當(dāng)我指定泛型時,提示的是在聲明過程中與泛型對應(yīng)的類型.
使用集合時用泛型聲明可以幫助你檢查集合中的類型,還能提示集合中應(yīng)存放的類型.
如何使用泛型
我們先看一下NSArray中泛型的使用


通過觀察發(fā)現(xiàn),泛型起到的作用就是占位符的作用.
聲明一個數(shù)組的指定泛型為NSString *, ObjectType就是一個占位符, 在接口中任何使用ObjectType泛型占位符的時候都會替換為NSString *類型.
了解了系統(tǒng)泛型使用方法然后自己創(chuàng)建一個ClassStack使用泛型.
@interface Stack <__covariant T> : NSObject
- (void)push:(T)obj;
- (T)pop;
@end
在聲明.h 我們都可以使用泛型T作為占位符.

在類擴(kuò)展和分類中并不能使用T泛型.
如果要做分類和類擴(kuò)展中使用泛型需要重新指定.

在實現(xiàn)中是不能使用泛型的.
限制泛型
通常我們在使用泛型時可以代替任意id類型,但有時我們使用泛型時,希望對泛型進(jìn)行限制,我們希望泛型為UIView類簇中的類型.

很顯然這并不是我們希望看到了,所以我們可以對泛型進(jìn)行限制
@interface Stack <__covariant T : UIView *> : NSObject
- (void)push:(T)obj;
- (T)pop;
@end

使用上面聲明方法可以解決問題.
同時也可以限制泛型遵守指定的協(xié)議
@interface Stack <__covariant T : id<protocol>> : NSObject
- (void)push:(T)obj;
- (T)pop;
@end
協(xié)變 逆變
在上面我們開到了關(guān)鍵字__covariant,下面就來看看這個關(guān)鍵字的作用
__covariant:協(xié)變, 子類轉(zhuǎn)父類 :也就是將子類的指針賦值給父類(多態(tài)的延伸)
__contravariant:逆變 父類轉(zhuǎn)子類:也就是將父類的指針賦值給子類(暫時沒有想到有什么作用,如果有哪位大佬知道歡迎指點一二).
在這里我們創(chuàng)建兩個類Animal和他的子類Dog.
//測試代碼
Stack <Dog *> *stack1 = [Stack new];
Stack <Animal *> *stack2 = [Stack new];
stack1 = stack2;
stack2 = stack1;
接下來我們分別來看看協(xié)變和逆變的特性.
// 逆變 父類指向子類
@interface Stack <__contravariant T : Animal *> : NSObject

// 協(xié)變 子類指向父類
@interface Stack <__covariant T : Animal *> : NSObject
