iOS9新特性常见关键字

iOS9新特性常见关键字

  • 关键字推出: 为迎合Swift语言, 在Swift中任何一个对象都需要约束是否为空
  • 关键字的好处: 提高开发规范
  • 关键字的作用: 在方法中才发挥作用

关键字在属性的使用

nullable: get方法的返回值, set方法的参数可以为空

1
2
3
4
5
6
7
nullable:get,set可能为空
方式一:
@property (nonatomic, strong, nullable) NSString *name;
方式二:
@property (nonatomic, strong) NSString * _Nullable name;
方式三:
@property (nonatomic, strong) NSString * __nullable name;

nonnull: get方法的返回值, set方法的参数都是非空的

1
2
3
4
5
nonnull:get,set非空
方式一:
@property (nonatomic ,strong, nonnull) NSString *name;
@property (nonatomic ,strong) NSString * _Nonnull name;
@property (nonatomic ,strong) NSString * __nonnull name;

null_resettable: get方法的返回值不可以为空, set方法的参数可以为空

1
2
3
4
null_resettable:set可以为空,get不可以为空
注意:必须要处理为nil的情况
方式一:
@property (nonatomic ,strong, null_resettable) NSString *name;
  • 会报警告, set方法没有处理可能为空的情况
  • 必须要处理为nil的情况, 重写get方法

Null_unspecified 不确定是否为空

在设置了上述三个关键字属性之后, 用点语法调用get/set方法时候, 不能确定调用的是get还是set, 也就不能确定能否为空

关键字在方法的使用

1
2
3
4
5
6
7
8
9
10
- (nonnull NSString *)test
{
return @"test";
}

- (NSString * _Nonnull)test
{
return @"test";
}

关键字的注意点:

  • 只能用于对象类型

  • NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END之间所有的对象都是nonnull

1
2
3
4
5
NS_ASSUME_NONNULL_BEGIN

// 在这个宏之间, 都是nonnull的

NS_ASSUME_NONNULL_END

iOS9新特性泛型

  • 泛型作用: 限制类型

  • 泛型在开发中的使用场景:

    • 用于集合(数组, 字典, NSSet)
    • 当声明一个类的时候, 某个属性不确定类型
  • 泛型好处

    • 提高开发规范, 一看就知道集合中放什么类型
    • 直接从集合中取出的对象可以知道是什么类型, 直接使用点语法
  • 泛型的书写

    • 如何声明泛型: 在声明一个类的时候, 在类型后面<泛型名称>

      1
      @interface NSArray<ObjectType> (NSExtendedArray)
    • 如何定义泛型: 在类型后面限制, <限制的类型>, 泛型的名称可以随意取

      1
      2
      3
      4
      5
      // 字典的key是字符串, value是id类型
      NSDictionary<NSString *, id> *dict;

      // 数组里是NSNumber类型
      NSArray<NSNumber *> *arr;
  • 注意

    • 并不是任何对象都能使用泛型
    • 泛型只用于方法调用
      • 因此在不可变数组里面泛型是没有意义的

自定义泛型(声明泛型)

1
2
3
4
5
6
7
8
9
10
#import <Foundation/Foundation.h>

@class Language;

// 声明泛型:不确定类型 ObjectType 随便取名
@interface Person< ObjectType> : NSObject

@property (nonatomic, strong) ObjectType language;

@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)viewDidLoad {
[super viewDidLoad];

Java *java = [[Java alloc] init];
iOS *ios = [[iOS alloc] init];

// iOS
Person<iOS *> *person = [[Person alloc] init];

person.language = ios;

// Java
Person *person1 = [[Person alloc] init];
person1.language = ios;

}

泛型中数据转换: 协变和逆变

__covariant 协变, 向上强转, 子类转父类

__contravariant 逆变, 向下强转, 父类转子类

1
2
3
4
5
6
Person<Language *> *p1 = [[Person alloc] init];
Person<iOS *> *p2 = [[Person alloc] init];

p1 = p2; // 子类转父类, 协变消除警告__covariant
p2 = p1; // 父类转子类, 逆变消除警告__contravariant

iOS9新特性 __kindof

__kindof, 用于修饰对象, 用于方法返回值, 描述返回类型是当前类或者子类

1
2
3
// 譬如该方法, __kindof关键字很好的解决了返回自定义cell的问题
// 返回值可以使UITableVCell, 也可以是其子类
- (__kindof UITableViewCell * _Nullable)dequeueReusableCellWithIdentifier:(NSString * _Nonnull)identifier

返回值类型的演变id –> instancetype –> __kindof

id:

  1. 不能使用点语法
  2. 能够调用任何对象的方法, 导致不能进行编译检查

instancetype:

  1. 会自动识别当前类的对象, 可以进行编译检查

但是, 不论id还是instancetype, 返回值并不知道返回的是什么类型, __kindof既解决了知道返回值类型的问题, 有解决了返回子类报警告的问题