Objective-C 泛型 协变 逆变

为什么要使用泛型

在使用NSArray, NSSet, NSDictionary 中都有使用泛型.

先来看一段没有使用泛型的的代码

NSMutableArray *arr = [NSMutableArray array];

[arr addObject:@1];

[arr addObject:@"wang"];

[arr addObject:@{}];

在这段代码中可以给数组中添加任意对象, 但是实际情况中我们希望使用数组用来保存同一种类型的变量.

实际情况中,我们可能希望使用数组保存一组NSString,但是我们操作失误在数组中添加的一个NSNumber使用上面的代码,在编译阶段,Xcode并不会提示错误或给出警告,但是在实际使用中,我们认为这个数组中都是NSString类型的变量,导致对NSNumber使用NSString的方法导致程序crash,显然这样的程序是不健壮的.

还好使用泛型可以解决这样的问题,代码如下

image.png

使用泛型指定数组中的类型为NSString,当我们在数组中添加其他类型时,就会出现提示.

image.png
image.png

在我们没有指定泛型时,提示显示可以添加id类型

当我指定泛型时,提示的是在声明过程中与泛型对应的类型.

使用集合时用泛型声明可以帮助你检查集合中的类型,还能提示集合中应存放的类型.


如何使用泛型

我们先看一下NSArray中泛型的使用

image.png
image.png

通过观察发现,泛型起到的作用就是占位符的作用.

声明一个数组的指定泛型为NSString *, ObjectType就是一个占位符, 在接口中任何使用ObjectType泛型占位符的时候都会替换为NSString *类型.

了解了系统泛型使用方法然后自己创建一个ClassStack使用泛型.

@interface Stack <__covariant T> : NSObject

- (void)push:(T)obj;

- (T)pop;

@end

在声明.h 我们都可以使用泛型T作为占位符.

image.png

在类扩展和分类中并不能使用T泛型.

如果要做分类和类扩展中使用泛型需要重新指定.

image.png

在实现中是不能使用泛型的.


限制泛型

通常我们在使用泛型时可以代替任意id类型,但有时我们使用泛型时,希望对泛型进行限制,我们希望泛型为UIView类簇中的类型.

image.png

很显然这并不是我们希望看到了,所以我们可以对泛型进行限制

@interface Stack <__covariant T : UIView *> : NSObject

- (void)push:(T)obj;

- (T)pop;

@end
image.png

使用上面声明方法可以解决问题.

同时也可以限制泛型遵守指定的协议

@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
image.png
// 协变 子类指向父类
@interface Stack <__covariant T : Animal *> : NSObject
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • object 变量可指向任何类的实例,这让你能够创建可对任何数据类型进程处理的类。然而,这种方法存在几个严重的问题...
    CarlDonitz阅读 934评论 0 5
  • 前言 泛型(Generics)的型变是Java中比较难以理解和使用的部分,“神秘”的通配符,让我看了几遍《Java...
    珞泽珈群阅读 7,926评论 12 51
  • 泛型是Java 1.5引入的新特性。泛型的本质是参数化类型,这种参数类型可以用在类、变量、接口和方法的创建中,分别...
    何时不晚阅读 3,057评论 0 2
  • 死磕自己,服务大众! 今天是天下的母亲节!祝天下的母亲节日快乐!本想回番禺和母亲过节,但在深圳儿子的母亲,儿子母亲...
    张锦全阅读 309评论 0 0
  • 有很多人都曾问过我,娱乐圈的人这么多,为什么偏偏只喜欢杨幂,我总是笑了笑,没有回答。因为我觉得欣赏一个人,或是因为...
    小傻lapin阅读 416评论 0 0