oc中添加了一些关键字,主要作用于编译期,对程序没有任何影响,相当于是一个提示。下面将结合Objective—C语言的新魅力——Nullability、泛型集合与类型延拓对oc的这些新特性进行研究。
Nullability检测的支持
可以使用nullable
关键字,表明该对象可以是空值;使用nonnull
关键字表明不可以是空对象。
1 | @property (nullable, nonatomic, strong) ObjectType firstObject; |
这是NSArray中的两个属性,其中nullable
关键字说明了这里可能返回空的值。
如果仅仅是在返回值中给开发者一些提示,你可能觉得应用并不大,是的,对开发者最大的帮助是这一特性可以用于函数的参数中,这样我们在调用函数时起到的提示作用,将是非常重要的,例如:
1 | -(void)setValue:(NSNumber * _Nonnull )number{ |
如果传入了空值,编译器会警告:
泛型的使用
这一特性和Nullability一样,只作用于编译期,是为我们开发者服务的另一重要特性。
有类型约定的集合
在Xcode7中,我们可以给集合类型添加一个泛型的约定,如下:
1 | NSMutableArray<NSString *> *array = [[NSMutableArray alloc]init]; |
声明了这样一个数组后,就告诉了编译器,这个数组中的数据类型都是NSString*类型的,可以使用该类型的方法,如:
在我们向这个数组中追加元素的时候,编译器将元素的类型提示了出来,并且将FromArray方法中需要的元素类型也提示了出来:
如果我们向这个数组中追加类型不匹配的元素,编译器会给我们一个这样的警告:
类型通配符
iOS的系统类中,大量使用了ObjectType
关键字,如下是系统的NSMutableArray
的头文件:
1 | @interface NSMutableArray<ObjectType> : NSArray<ObjectType> |
这个ObjectType
就是泛型的类型标识符,我们可以用它自己定义一个集合类,如包装一个NSSarray:
1 | @interface MyArray<Type> : NSObject |
实现如下:
1 | - (instancetype)init |
注意:
- 这个类型通配符只能在interfave里使用,作用域为@interface到@end之间。
- 实现时,对于定义的
Type
类型的参数,使用id
代替。 - 泛型
Type
不用写成Type *
。 - 对于多参的集合,将参数类型用“,”隔开即可,如
NSMultableDictionary<NSString * ,NSString *> *dic = [[NSMultableDictionary alloc] init];
泛型和协议
声明
泛型和协议都是用尖括号括起来的,可能会很困扰,编译器如何知道哪个是泛型哪个是协议。其实它们是有规则的。简单看一下例子:
1 | @protocol proc |
我们看到,所有的类都是要有一个基类,所以泛型的尖括号是在基类之前的,基类之后可以写上协议,使用的时候就可以 Test<SomeType *> test
这样用啦。那如果基类也有泛型需要声明呢?比如 NSMutableArray
:
1 | @interface NSMutableArray<ObjectType> : NSArray<ObjectType> |
类似于这种的泛型,我们就不能直接申明协议了。但是我们可以变通一下,可以为这个类创建一个分类,在分类中声明协议啊。
另外还有一点,协议中是不能使用泛型的,如果实在想用,拥抱 Swift 吧。
使用
使用的时候一般情况下都是表示泛型,比如:
1 | Test<NSString *> test = [[Test alloc] init]; |
但是也有表示协议的,不过局限在 id 类型,比如:
1 | id<SomeProtocol> prop; |
表示任意一个实现了某个协议的类型。
__kindof
在小类向大类赋值时,往往没有任何问题。但是大类向小类赋值时,就会产生警告。譬如UIView
的实例view
和UIButton
的实例button
,可以view = button
,但是最好不要button = view
。如果想要使用,又不希望产生警告怎么办?使用__kindof
。1
2
3UIButton *b = [[UIButton alloc] init];
__kindof UIView *view = [[UIButton alloc]init];
b = view;
这里,由于view
使用__kindof
表示UIView
的子类,不会产生警告。否则要进行强转b = (UIButton *)view;