美文网首页
Objective-C 范型

Objective-C 范型

作者: Don_He | 来源:发表于2019-04-03 16:11 被阅读0次

系统库范型

Objective C支持轻量级的范型。在编写自定义的范型类之前,我们先来看看Cocoa Touch的集合类(NSArray,NSDictionary,NSSet)对于范型的支持。

首先创建一个数组,这个数组只应该用来存储字符串:

NSMutableArray * array = [[NSMutableArray alloc] init];
[array addObject:@"1"];
//误加了一个非字符串类型进去
[array addObject:@(0)];

这时候,对数组中元素进行遍历,Crash:

for (NSString *string in array) {
    NSInteger length = [string length];
}

Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[__NSCFNumber length]: unrecognized selector sent to instance’

如果编译器能帮助我们来确保加入数组中的元素都是String就好了

范型可以帮助我们解决这个问题:

//创建一个保存字符串的数组
NSMutableArray<NSString *> * array = [[NSMutableArray alloc] init];
[array addObject:@"1"];
[array addObject:@(0)];

同样的,NSDictionary和NSSet也支持范型:

NSDictionary<NSString *, NSString *> *dictionary;
NSSet<NSString *> *set;

自定义范型类型

自定义一个范型类型很简单,和其他语言类似,在声明类的时候声明占位符即可:

声明一个Cup容器,用来存储一个值:

// Box.h
@interface Box<ObjectType> : NSObject

@property (nonatomic, readonly) ObjectType value;

- (void)seal:(ObjectType)value;

@end
// Box.m
@interface Box()

@property (strong, nonatomic) id value;

@end

@implementation Box

- (void)seal:(id)value{
    _value = value;
}

@end

接着,我们就可以这样使用,

Box<NSString *> * box = [[Box<NSString *> alloc] init];
[box seal:@"1234"];
[box seal:@(1)]; // Warning

关于Objective C范型的几点说明:

  • 在头文件的类声明中添加占位符ObjectType
  • 在.m文件中无法使用范型占位符,用id类型替代即可

约束

Objective 可以为范型增加轻量级的约束,比如要求ObjectType实现NSCopying协议:

@interface Box<ObjectType:id<NSCopying>> : NSObject

那么,只有实现NSCopying的类型才能够通过编译:

//Error
Box<NSObject *> * box1 = [[Box<NSObject *> alloc] init];
//Work
Box<NSString *> * box2 = [[Box<NSString *> alloc] init];

逆变与协变

创建一个ViewBox和LabelBox,并且把LabelBox赋值给ViewBox

Box<UIView *> * viewBox = [[Box alloc] init];
Box<UILabel *> * labelBox = [[Box alloc] init];
viewBox = labelBox; // Warning

这看似合理,又不合理。

  • 合理是因为两个Box中容纳的类型不一样,赋值的时候类型检查不通过。
  • 不合理是因为根据里氏替换原则,一个容纳UILabel的Box,那么也应该是一个容纳UIView的Box。

协变

协变由关键字__covariant声明。一个协变类型的范型占位符,如果变量A的占位符类型是子类,那么可以把它赋值给占位符类型是父类的B。

也就是说,通过协变,我们能够解决:一个容纳UILabel的Box,那么也应该是一个容纳UIView的Box。

// Box.h
@interface Box<__covariant ObjectType> : NSObject

@property (nonatomic, readonly) ObjectType value;

- (void)seal:(ObjectType)value;

@end

协变常常用于容器类型,像系统的NSArray,NSDictionary,NSSet都采用了协变:

逆变

逆变(__contravariant),一个逆变类型的范型占位符,如果变量A的占位符类型是父类,那么可以把它赋值给占位符类型是子类的B。

逆变更侧重类型的行为.

举个例子:

//用来解析字符串中的数字
@interface StringPaser<__contravariant ObjectType:NSString *> : NSObject

- (NSString *)paseNumber;

@end

那么以下代码则不会有编译器警告

StringPaser<NSString *> * stringPaser = [[StringPaser alloc] init];
StringPaser<NSMutableString *> * mutableStringPaser = [[StringPaser alloc] init];
//父类赋值给子类
mutableStringPaser = stringPaser;

逆变要求父类和子类能够提供同样的行为,所以通过父类的接口创建的范型类,可以用来处理子类。

相关文章

  • Objective-C 范型

    系统库范型 Objective C支持轻量级的范型。在编写自定义的范型类之前,我们先来看看Cocoa Touch的...

  • Objective-C->编程语言

    Objective-C[编辑]维基百科,自由的百科全书 Objective-C编程范型面向对象 设计者布莱德·考克...

  • Xamarin for Objective-C开发者

    属性 Objective-C C# Get Set Objective-C C# 泛型 Objective-C C...

  • CoreJava笔记 - 范型程序设计(2)

    范型代码和Java虚拟机 关键知识:类型擦除Java的范型是编译器层次的范型,而在Java虚拟机上并没有范型类。在...

  • 范型

    <:上界 >:下界 <%视图定界 一定要传隐式转换函数 T隐式转换成order[T][T<%M]关系意味着...

  • 范型

    范型就是不指定类型,用的时候在指定类型使用场景 用在构造函数中

  • 范型

    泛型是jdk1.5使用的新特性。 泛型的好处:1. 将运行时的异常提前至了编译时。2. 避免了无谓的强制类型转换 ...

  • 范型

  • CoreJava笔记 - 范型程序设计(5)

    反射与范型 由于类型擦除,反射无法得到关于范型类型参数的信息。 范型的Class类在Java的反射库中,Class...

  • Flutter 类方法和基础语法(II) - 范型

    范型限制

网友评论

      本文标题:Objective-C 范型

      本文链接:https://www.haomeiwen.com/subject/hhjzbqtx.html