为什么要使用泛型
在使用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

网友评论