zoukankan      html  css  js  c++  java
  • 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 *> ,尖括号内部即为泛型类型
    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 ,告诉编译器,这样转换没有问题。

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

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

  • 相关阅读:
    shell基础之更改IP
    shell基础之if语句
    shell基础之变量及表达式
    shell基础之shell相关概念
    shell基础之bus实战(if 练习)
    shell基础之pxe批量部署
    shell基础之编译安装nginx
    Razor视图引擎基础语法
    EF三层
    EF简单增删改查
  • 原文地址:https://www.cnblogs.com/SoulKai/p/5945905.html
Copyright © 2011-2022 走看看