夏树正茂

花有重开日,人无再少年.

Nullable和__kindof的使用

| Comments

nullable和__kindof的使用记录

2015年的WWDC里面介绍了几个新的关键字:__kindofnullable。如果能很好的使用它们,编译器在我们犯错误的时候就能给予我们提示,将bug扼杀在摇篮里。

__kindof

__kindof关键字的使用很简单,直接上一个示例代码就能说明白:

1
2
3
4
5
6
7
8
9
10
11
NSMutableArray<UIView *> *subviews = [[NSMutableArray alloc] init];

[subviews addObject:[[UIView alloc] init]]; // Works
[subviews addObject:[[UIImageView alloc] init]]; // Also works

UIView *sameView = subviews[0]; // Works
UIImageView *sameImageView = subviews[1]; // Incompatible pointer types initializing 'UIImageView *' with an expression of type 'UIView *'

NSLog(@"%@", NSStringFromClass([sameView class])); // UIView
NSLog(@"%@", NSStringFromClass([sameImageView class])); // UIImageView
  

上面的代码在编译的时候会给出警告,运行的时候不会crash,下面是使用__kindof的示例:

1
2
3
4
5
6
7
8
9
10
11
NSMutableArray<__kindof UIView *> *subviews = [[NSMutableArray alloc] init];

[subviews addObject:[[UIView alloc] init]]; // Works
[subviews addObject:[[UIImageView alloc] init]]; // Also works

UIView *sameView = subviews[0]; // No problem
UIImageView *sameImageView = subviews[1]; // No complaints now!

NSLog(@"%@", NSStringFromClass([sameView class])); // UIView
NSLog(@"%@", NSStringFromClass([sameImageView class])); // UIImageView
  

可以看到在使用了__kindof关键字后,不在有编译警告了,所以对于Objective-C新提供的这个关键字来说,它可以限定返回值或者参数以及像我们例子中的这种泛型的类型,要么是这种类型本身的类型,要么是它的subClass,反之就会给出警告。

nullable、_Nullable、__nullable

这些关键字可以限定参数或者返回值可以空。它们的作用相同,但是也有细微的使用差别。

  1. _NullableXcode7以后用来替代__nullable的,所以能使用__nullable的地方就可以使用_Nullable
  2. nullable放在类型之前,_Nullable放在类型之后。

以下的示例都是正确并且作用都是等价的:

1、修饰返回值:

1
2
3
4
- (nullable NSNumber *)result
- (NSNumber * __nullable)result
- (NSNumber * _Nullable)result
  

2、修饰参数:

1
2
3
4
- (void)doSomethingWithString:(nullable NSString *)str
- (void)doSomethingWithString:(NSString * _Nullable)str
- (void)doSomethingWithString:(NSString * __nullable)str
  

3、修饰property:

1
2
3
4
@property(nullable) NSNumber *status
@property NSNumber *__nullable status
@property NSNumber * _Nullable status
  

4、修饰指针的指针,不能使用nullable

1
2
3
- (void)compute:(NSError *  _Nullable * _Nullable)error
- (void)compute:(NSError *  __nullable * _Null_unspecified)error
  

5、修饰block:

1
2
3
4
- (void)executeWithCompletion:(nullable void (^)())handler
- (void)executeWithCompletion:(void (^ _Nullable)())handler
- (void)executeWithCompletion:(void (^ __nullable)())handler
  

6、结论:
__nullable、_Nullable、nullable以及与它们对应的__nonnull、_Nonnull、nonnull一样,只需要注意它们相对于修饰类型的位置。

Comments