文档章节

iOS泛型

H
 HeroHY
发布于 2017/07/04 18:04
字数 1513
阅读 12
收藏 0

  

  这一篇文章主要来介绍泛型的意义、使用与声明方法等。

1.泛型:限制类型

  1.1.泛型使用场景:

    1.在集合(数组NSArray、字典NSDictionary、集合NSSet)中使用泛型比较常见。

    2.当声明一个类,但是类里面的某些属性的类型不确定的时候,我们才使用泛型。

  1.2.泛型书写规范

    在类型后面定义泛型:NSMutableArray<UITouch *> dataArray

  1.3.泛型修饰

    只能修饰方法的调用。

  1.4.泛型好处:

    1.提高开发的规范,减少程序员之间的交流。

    2.通过集合取出来的对象,可以直接当做泛型对象使用。这样我们就可以直接使用.点语法。

  

2.代码使用泛型:

  2.1.声明一个泛型为NSString的数组

1 // 具体做法就是在 NSMutableArray 后带一个 <NSString *> ,尖括号内部即为泛型类型
2 @property (nonatomic, strong, nullable) NSMutableArray<NSString *> *dataArray;

  2.2.当我们要给数组添加对象或取出对象的时候,系统就会自动提示应该传入或者取出来的对象的类型,这个类型就是你刚才声明的泛型类型

复制代码

1     // 1.没有使用泛型
 2 //    [self.dataArray addObject:<#(nonnull id)#>];
 3 
 4     // 2.使用泛型
 5 //    [self.dataArray addObject:<#(nonnull NSString *)#>];
 6     
 7     // 3.添加不正确的类型,会出现警告
 8 //    [self.dataArray addObject:@1];
 9     
10     // 4.我们可以直接将集合中取出来的对象当做泛型使用
11     NSInteger length = [self.dataArray.firstObject length];

复制代码

  

  基本上实现了使用泛型过程中可能出现的情况。

 

3.泛型的自定义

  刚才我们只是实现了系统类NSMutableArray的泛型。接下来我们要考虑下,我们怎么样在我们自己的类中声明一个泛型的属性呢?

  为了这个目的,我们创建一个 Language 的类表示 “语言”。并且创建两个 Language 的子类,分别叫 Java 和 IOS 。很明显这两个是“某一个类型的语言”。我们创建一个Person的类,给类声明一个泛型,在类的 .h 文件中声明一个声明一个属性,这个属性表示这个人会的语言,即为 IOS 或者 Java 。那么我们有以下两种声明方式:  

1 // 语言
2 // 1.id:任何对象都能传进来
3 //@property (nonatomic, strong, null_unspecified) id language;
4 // 2.Language:在外面调用的时候不能提示具体是哪种语言
5 //@property (nonatomic, strong, null_unspecified) Language *language;

  因为 Language 这个语言并不能代表这个 Person 究竟会什么语言,我们需要的属性时 IOS 和 Java。这两种都可以在调用的时候传入 Java 和 IOS 两种对象,但它们的缺点也非常明显,若使用 id 则我们可以传入任何对象,而不只是 Java 和 IOS ;使用 Language * 呢,我们没有办法在编译的时候确定这个人究竟会什么语言,而只能在运行时判断。有没有办法让我们在编译的时候就能知道 Person 具体会哪种 Language 呢?

  办法就是泛型。

  声明自定义类的泛型,我们需要做这样一步:

1 // (给类)声明一个泛型
2 @interface JTPerson<ObjectType> : NSObject

  看出区别了吗?我们在 interface 类名之后加了一对尖括号 <> ,中间是 ObjectType 。这个就代表泛型。这样我们在声明属性的时候就可以这么写: 

1 @property (nonatomic, strong, null_unspecified) ObjectType language;

  也就是,我们现在不指定具体的类型,而在实例化这个类的时候确定这个泛型。若不确定,那么所有的 ObjectType 会自动变成 id 。像这样:

复制代码

1     // iOS
 2     JTPerson<IOS *> *iOSP = [[JTPerson alloc] init];
 3      
 4 //    [iOSP setLanguage:@"123"];
 5     
 6 //    [iOSP setLanguage:<#(IOS * _Null_unspecified)#>];
 7     
 8 //    [iOSP setLanguage:[[Java alloc] init]];
 9     
10     // Java
11     JTPerson<Java *> *javaP = [[JTPerson alloc] init];
12     
13 //    [javaP setLanguage:@"123"];
14     
15 //    [javaP setLanguage:<#(Java * _Null_unspecified)#>];
16     
17 //    [javaP setLanguage:[[IOS alloc] init]];

复制代码

  这样,我们在声明 Person这个类的时候,就顺便声明了这个类的泛型。这样系统就会在你使用到泛型的属性与方法的时候,自动提醒你声明的泛型类型了。

 

4.泛型的协变与逆变

  首先我们来看一个方法:

1 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
2     
3     [touches anyObject];
4 }

  大家应该很熟悉这个方法了。这就是 UIViewController 继承自 UIResponder 的方法,是点击这个视图控制器之后事件链的最后一环。这时候经过上面的学习,我们会看到这其中就使用了泛型: (NSSet<UITouch *> *) 。这样我们点进集合 NSSet 会发现它是这样写的:

  前后我们都很清楚: interface:声明;NSSet:集合;ObjectType:泛型;NSObject:是NSSet的父类,也是根类;后面尖括号中表示的是遵守的协议。

  那么 __covariant 代表什么?

  这里我们先来学习两个单词: covariant:协变的 contravariant:逆变的。

  那么 __covariant协变 代表什么?

 

  我们来试一下。在刚才的自定义类 Person 的泛型 ObjectType 前加这样一条修饰: __covariant

1 @interface JTPerson<__covariant ObjectType> : NSObject

  然后在调用的时候,我们声明两个实例,泛型分别为父类 Language 和子类 IOS。这样若泛型为 IOS 的 Person 想给泛型为 Language 的 Person 赋值,会怎么样:

复制代码

1     // 1.协变
2     // iOS
3     JTPerson<IOS *> *iOSP = [[JTPerson alloc] init];
4     
5     // Language
6     JTPerson<Language *> *p = [[JTPerson alloc] init];
7     
8     // 如果子类想给父类赋值,协变
9     p = iOSP;

复制代码

  并没有报错。

  也就是说,若泛型为子类的对象想给泛型为父类的对象赋值的时候,我们需要在泛型前面添加 协变__convariant ,告诉编译器,这样转换没有问题。

  同理,__contravariant逆变就是若泛型为父类的对象想给泛型为子类的对象赋值的时候,我们需要在泛型前面添加 逆变__contravariant ,告诉编译器,这样转换没有问题。

  这就是协变与逆变的含义。

  协变与逆变本身是面向对象继承的语言的一个特性,也并不只应用在泛型这里。

© 著作权归作者所有

共有 人打赏支持
H
粉丝 2
博文 138
码字总数 67501
作品 0
海淀
unity中使用protobuffer作为网络通讯封包协议的实现和流程

一 使用的库 protobuffer 有两个c#实现,其中protobuffer-csharp 这个版本 比较适合跨语言开发,这个版本模仿java 实现;在ios上面,我们要使用 lite 版本,同时需要修改代码 却掉 pluginre...

李勇2
2015/02/28
0
0
马云辟谣被迫离职;阿里又又又越狱了 iOS 12;Safari 再爆漏洞 | 极客头条

「CSDN 极客头条」,是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报道。风里雨里,我们将每天为朋友们,播报最新鲜有料的新闻资讯,让所有技术人,时刻紧跟业界潮流。 ...

CSDN资讯
09/18
0
0
iOS 12 真的能让旧款 iPhone 速度飞起吗?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdnnews/article/details/82757910 去年 9 月,苹果在发布 iOS 11 时曾表示,这是先进移动操作系统 iOS 的又...

CSDN资讯
09/18
0
0
【AR】开始使用Vuforia开发iOS(2)

原 设置iOS开发环境 安装Vuforia iOS SDK 如何安装Vuforia iOS示例 编译并运行Vuforia iOS示例 支持iOS金属 iOS 64位迁移 设置iOS开发环境 适用于iOS的Vuforia引擎目前支持运行iOS 9及更高版...

lichong951
06/11
0
0
iOS 12.1 Beta 1释出!比正式版更流畅

这星期开卖的 iPhone XS 系列,能否炒起尚是未知之数,惟近日不断传出 iPhone XS 炒价有利消息,令不少果农皆感雀跃。只是对于自用者来说,iPhone XS 炒价多少,完全不感兴趣,最重要是能用正...

小七里外
09/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

awk命令扩展使用操作

awk 中使用外部shell变量 示例1 [root@centos01 t1022]# A=888[root@centos01 t1022]# echo "" | awk -v GET_A=$A '{print GET_A}'888[root@centos01 t1022]# echo "aaaaaaaaaaaaa" | aw......

野雪球
17分钟前
4
0
深入解析MySQL视图VIEW

Q:什么是视图?视图是干什么用的? A:视图(view)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。作为一个select语句保存在数据字典中的。   通过视图,可以展现基表的部分数据;...

IT--小哥
今天
5
0
虚拟机学习之二:垃圾收集器和内存分配策略

1.对象是否可回收 1.1引用计数算法 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时候计数器值为0的对象就是不可能...

贾峰uk
今天
6
0
smart-doc功能使用介绍

smart-doc从8月份底开始开源发布到目前为止已经迭代了几个版本。在这里非常感谢那些敢于用smart-doc去做尝试并积极提出建议的社区用户。因此决定在本博客中重要说明下smart-doc的功能,包括使...

上官胡闹
昨天
12
0
JavaEE——Junit

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 Junit Junit又名单元测试,Junit是用来测试Jav...

凯哥学堂
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部