iOS学习笔记(01) - 泛型
决定新开一坑,在不断学习的同时分享自己的学习历程给大家,既是对自己学习的记录,又希望能对大家提供些微的帮助。
这一篇文章主要来介绍泛型的意义、使用与声明方法等。
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 *> ,尖括号内部即为泛型类型
@property (nonatomic, strong, nullable) NSMutableArray<NSString *> *dataArray;
2.2.当我们要给数组添加对象或取出对象的时候,系统就会自动提示应该传入或者取出来的对象的类型,这个类型就是你刚才声明的泛型类型
// 1.没有使用泛型
// [self.dataArray addObject:<#(nonnull id)#>]; // 2.使用泛型
// [self.dataArray addObject:<#(nonnull NSString *)#>]; // 3.添加不正确的类型,会出现警告
// [self.dataArray addObject:@1]; // 4.我们可以直接将集合中取出来的对象当做泛型使用
NSInteger length = [self.dataArray.firstObject length];

基本上实现了使用泛型过程中可能出现的情况。
3.泛型的自定义
刚才我们只是实现了系统类NSMutableArray的泛型。接下来我们要考虑下,我们怎么样在我们自己的类中声明一个泛型的属性呢?
为了这个目的,我们创建一个 Language 的类表示 “语言”。并且创建两个 Language 的子类,分别叫 Java 和 IOS 。很明显这两个是“某一个类型的语言”。我们创建一个Person的类,给类声明一个泛型,在类的 .h 文件中声明一个声明一个属性,这个属性表示这个人会的语言,即为 IOS 或者 Java 。那么我们有以下两种声明方式:
// 语言
// 1.id:任何对象都能传进来
//@property (nonatomic, strong, null_unspecified) id language;
// 2.Language:在外面调用的时候不能提示具体是哪种语言
//@property (nonatomic, strong, null_unspecified) Language *language;
因为 Language 这个语言并不能代表这个 Person 究竟会什么语言,我们需要的属性时 IOS 和 Java。这两种都可以在调用的时候传入 Java 和 IOS 两种对象,但它们的缺点也非常明显,若使用 id 则我们可以传入任何对象,而不只是 Java 和 IOS ;使用 Language * 呢,我们没有办法在编译的时候确定这个人究竟会什么语言,而只能在运行时判断。有没有办法让我们在编译的时候就能知道 Person 具体会哪种 Language 呢?
办法就是泛型。
声明自定义类的泛型,我们需要做这样一步:
// (给类)声明一个泛型
@interface JTPerson<ObjectType> : NSObject
看出区别了吗?我们在 interface 类名之后加了一对尖括号 <> ,中间是 ObjectType 。这个就代表泛型。这样我们在声明属性的时候就可以这么写:
@property (nonatomic, strong, null_unspecified) ObjectType language;
也就是,我们现在不指定具体的类型,而在实例化这个类的时候确定这个泛型。若不确定,那么所有的 ObjectType 会自动变成 id 。像这样:
// iOS
JTPerson<IOS *> *iOSP = [[JTPerson alloc] init]; // [iOSP setLanguage:@"123"]; // [iOSP setLanguage:<#(IOS * _Null_unspecified)#>]; // [iOSP setLanguage:[[Java alloc] init]]; // Java
JTPerson<Java *> *javaP = [[JTPerson alloc] init]; // [javaP setLanguage:@"123"]; // [javaP setLanguage:<#(Java * _Null_unspecified)#>]; // [javaP setLanguage:[[IOS alloc] init]];

这样,我们在声明 Person这个类的时候,就顺便声明了这个类的泛型。这样系统就会在你使用到泛型的属性与方法的时候,自动提醒你声明的泛型类型了。
4.泛型的协变与逆变
首先我们来看一个方法:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[touches anyObject];
}
大家应该很熟悉这个方法了。这就是 UIViewController 继承自 UIResponder 的方法,是点击这个视图控制器之后事件链的最后一环。这时候经过上面的学习,我们会看到这其中就使用了泛型: (NSSet<UITouch *> *) 。这样我们点进集合 NSSet 会发现它是这样写的:
前后我们都很清楚: interface:声明;NSSet:集合;ObjectType:泛型;NSObject:是NSSet的父类,也是根类;后面尖括号中表示的是遵守的协议。
那么 __covariant 代表什么?
这里我们先来学习两个单词: covariant:协变的 contravariant:逆变的。
那么 __covariant协变 代表什么?
我们来试一下。在刚才的自定义类 Person 的泛型 ObjectType 前加这样一条修饰: __covariant
@interface JTPerson<__covariant ObjectType> : NSObject
然后在调用的时候,我们声明两个实例,泛型分别为父类 Language 和子类 IOS。这样若泛型为 IOS 的 Person 想给泛型为 Language 的 Person 赋值,会怎么样:
// 1.协变
// iOS
JTPerson<IOS *> *iOSP = [[JTPerson alloc] init]; // Language
JTPerson<Language *> *p = [[JTPerson alloc] init]; // 如果子类想给父类赋值,协变
p = iOSP;
并没有报错。
也就是说,若泛型为子类的对象想给泛型为父类的对象赋值的时候,我们需要在泛型前面添加 协变__convariant ,告诉编译器,这样转换没有问题。
同理,__contravariant逆变就是若泛型为父类的对象想给泛型为子类的对象赋值的时候,我们需要在泛型前面添加 逆变__contravariant ,告诉编译器,这样转换没有问题。
这就是协变与逆变的含义。
协变与逆变本身是面向对象继承的语言的一个特性,也并不只应用在泛型这里。
iOS学习笔记(01) - 泛型的更多相关文章
- ios学习笔记01
## HUD - 其他说法:指示器.遮盖.蒙板 - 半透明HUD的做法 - 背景色设置为半透明颜色 ## 定时任务 - 方法1:performSelector ```objc // 1.5s后自动调用 ...
- iOS学习笔记10-UIView动画
上次学习了iOS学习笔记09-核心动画CoreAnimation,这次继续学习动画,上次使用的CoreAnimation很多人感觉使用起来很繁琐,有没有更加方便的动画效果实现呢?答案是有的,那就是UI ...
- iOS学习笔记——AutoLayout的约束
iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...
- 软件测试之loadrunner学习笔记-01事务
loadrunner学习笔记-01事务<转载至网络> 事务又称为Transaction,事务是一个点为了衡量某个action的性能,需要在开始和结束位置插入一个范围,定义这样一个事务. 作 ...
- IOS学习笔记25—HTTP操作之ASIHTTPRequest
IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...
- IOS学习笔记之关键词@dynamic
IOS学习笔记之关键词@dynamic @dynamic这个关键词,通常是用不到的. 它与@synthesize的区别在于: 使用@synthesize编译器会确实的产生getter和setter方法 ...
- iOS学习笔记-精华整理
iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...
- iOS学习笔记总结整理
来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...
- iOS学习笔记之Category
iOS学习笔记之Category 写在前面 Category是类别(也称为类目或范畴),使用Category,程序员可以为任何已有的类添加方法.使用类别可以对框架提供的类(无法获取源码,不能直接修改) ...
随机推荐
- CentOS 7中将Tomcat设置为系统服务
tomcat 需要增加一个pid文件,在tomca/bin 目录下面,增加 setenv.sh 配置,catalina.sh启动的时候会调用,在该文件中添加如下内容 CATALINA_PID=&quo ...
- 一步步优化JVM一:概述、方法及需求
现代JVM是一个具有灵活适应各种应用能力的软件,尽管很多应用能够在JVM的默认配置下运行良好,但是有些应用还是需要优化JVM配置以达到其性能要求.由于各种各样的应用能够运行在现在JVM上面,所以大量的 ...
- 2016 Vultr VPS最新优惠码,赠送新用户70美元,亲测有效
vultr肯定疯了,从来没有哪家海外vps像vultr那么大力度的优惠.近期,vultr vps再度推出优惠码,任何新用户注册即送20美元!要知道,vultr vps最便宜的vps套餐只要5美元/月, ...
- H264的coded_block_pattern编码块模式
1 词汇约定 CodedBlockPatternLuma:一个宏块的亮度分量的coded_block_pattern CodedBlockPatternChroma:一个宏块的色度分量的coded_b ...
- 在Eclipse中安装testNG插件
1. 选择菜单:Help->Install New Software,点击Add按钮输入框中输入相应的Name:testNG和Location:http://beust.com/eclipse. ...
- B-number
B-number 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3652 数位dp 这题是暑期集训的时候做的,昨天补了数位dp的记忆化搜索做法,把艾神的 ...
- Fox And Jumping
Fox And Jumping 题目链接:http://codeforces.com/problemset/problem/512/B dp 若所选卡片能到达区间内任意点,那么所选卡片的最大公约数为1 ...
- 说说SACC2016第八届架构师大会
每年这方面的会议很多,不知不觉已经连续举办八年了.一届比一届办的有质量,规模越大.今年也如约而至.2016-10-27在北京万达索菲特酒店.4000多人规模,云集各领域顶尖架构师,运维,云计算,技术专 ...
- 《JS权威指南学习总结--第九章 类和模板》
内容要点: 一. 1.第六章详细介绍了JS对象,每个JS对象都是一个属性集合,相互之间没有任何联系.在JS中也可以定义对象的类,让每个对象都共享某些属性,这种"共享"的特性是非常有 ...
- IE6/IE7浏览器不支持display: inline-block;的解决方法
display: inline-block;在IE6与IE7中存在bug. 1.inline元素的display属性设置为inline-block时,所有的浏览器都支持: 2.block元素的disp ...