决定新开一坑,在不断学习的同时分享自己的学习历程给大家,既是对自己学习的记录,又希望能对大家提供些微的帮助。

  

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

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) - 泛型的更多相关文章

  1. ios学习笔记01

    ## HUD - 其他说法:指示器.遮盖.蒙板 - 半透明HUD的做法 - 背景色设置为半透明颜色 ## 定时任务 - 方法1:performSelector ```objc // 1.5s后自动调用 ...

  2. iOS学习笔记10-UIView动画

    上次学习了iOS学习笔记09-核心动画CoreAnimation,这次继续学习动画,上次使用的CoreAnimation很多人感觉使用起来很繁琐,有没有更加方便的动画效果实现呢?答案是有的,那就是UI ...

  3. iOS学习笔记——AutoLayout的约束

    iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...

  4. 软件测试之loadrunner学习笔记-01事务

    loadrunner学习笔记-01事务<转载至网络> 事务又称为Transaction,事务是一个点为了衡量某个action的性能,需要在开始和结束位置插入一个范围,定义这样一个事务. 作 ...

  5. IOS学习笔记25—HTTP操作之ASIHTTPRequest

    IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...

  6. IOS学习笔记之关键词@dynamic

    IOS学习笔记之关键词@dynamic @dynamic这个关键词,通常是用不到的. 它与@synthesize的区别在于: 使用@synthesize编译器会确实的产生getter和setter方法 ...

  7. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  8. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

  9. iOS学习笔记之Category

    iOS学习笔记之Category 写在前面 Category是类别(也称为类目或范畴),使用Category,程序员可以为任何已有的类添加方法.使用类别可以对框架提供的类(无法获取源码,不能直接修改) ...

随机推荐

  1. python 数据清洗之数据合并、转换、过滤、排序

    前面我们用pandas做了一些基本的操作,接下来进一步了解数据的操作, 数据清洗一直是数据分析中极为重要的一个环节. 数据合并 在pandas中可以通过merge对数据进行合并操作. import n ...

  2. jquery一个简单的菜单小插件

    刚学会封装插件,先来封装一个小的菜单插件 html部分 <ul class="zong"> <li class="yiji"> < ...

  3. kubernetes port nodePort targetPort 理解

    port The port that the service is exposed on the service's cluster ip (virsual ip). Port is the serv ...

  4. 微信小程序开发详解——小程序,大颠覆!

    微信小程序开发 联系 苏念 188.1414.7927  微信小程序系统开发 微信新功能开发 小程序开发 小程序怎么开发 app小程序开发 简化小程序开发 微信小程序定制 小程序制作 开发微信小程序  ...

  5. SEO定义目的,优化的好处

    SEO:search engine optimization(搜索引擎优化) SEO严谨的定义:SEO是指在了解搜索引擎自然排名机制的基础上,对网站进行内部及外部的调整优化,改进网站在搜索引擎中关键字 ...

  6. Weex-进阶笔记二

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica; color: #945200 } p.p2 { margin: 0.0p ...

  7. 使用ajax和urlconnection方式调用webservice服务

    <html> <head> <title>使用ajax方式调用webservice服务</title> <script> var xhr = ...

  8. SNS

    SNS,专指社交网络服务.也指社交现有已成熟普及的信息载体,如短信SMS服务.SNS的另一种常用解释:全称Social Network Site,即“社交网站”或“社交网”.SNS也指Social N ...

  9. ios @property

    参考资料 http://blog.csdn.net/pingchangtan367/article/details/14000315 http://blog.csdn.net/xdrt81y/arti ...

  10. 数据库 Mysql内容补充一

    mysql时间函数 --获取当前日期 select current_date(); --获取当前时间 select current_time(); --获取当前的日期和时间 select now(); ...