Objective-C中的一些修饰符
__kindof
__kindof 这修饰符很实用的,解决了一个长期以来的小痛点,拿原来的 UITableView 的这个方法来说:
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
使用时前面基本会使用 UITableViewCell 子类型的指针来接收返回值,所以这个 API 为了让开发者不必每次都蛋疼的写显式强转,把返回值定义成了 id 类型,而这个 API 实际上的意思是返回一个 UITableViewCell 或 UITableViewCell 子类的实例,于是新的 __kindof 关键字解决了这个问题:
- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
既明确表明了返回值,又让使用者不必写强转。再举个带泛型的例子,UIView 的 subviews 属性被修改成了:
@property (nonatomic, readonly, copy) NSArray<__kindof UIView *> *subviews;
这样,写下面的代码时就没有任何警告了:
UIButton *button = view.subviews.lastObject;
nullability annotations(空性修饰符)
苹果在Xcode 6.3引入的一个Objective-C的新特性
nonnull:非空
nullable:可空
null_resettable: setter nullable,但是 getter nonnull(注意:如果使用null_resettable,必须 重写get方法或者set方法,处理传递的值为空的情况)
最直观例子就是 UIViewController 中的 view 属性:
@property (null_resettable, nonatomic, strong) UIView *view;
__null_unspecified:不能确定是否为空
基本用法:
//三种使用方式都可以
@property (nonatomic, copy, nonnull) NSString *name;
@property (nonatomic, copy) NSString * _Nonnull name;
@property (nonatomic, copy) NSString * __nonnull name;
//补充(不适用于assign属性,因为它是专门用来修饰指针的)
@property (nonatomic, assign) NSUInteger age;
//补充(用下面宏包裹起来的属性全部都具nonnull特征,当然,如果其中某个属性你不希望有这个特征,也可以自己定义,比如加个nullable)
//在NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END之间,定义的所有对象属性和方法默认都是nonnull
//也可以在定义方法的时候使用
//返回值和参数都不能为空
- (nonnull NSString *)test:(nonnull NSString *)name;
//同上
- (NSString * _Nonnull)test1:(NSString * _Nonnull)name;
===========================null_resettable============================
@property (nonatomic, copy, null_resettable) NSString *name;
- (void)setName:(NSString *)name {
if (name == nil) {
name = @"XXX";
}
_name = name;
}
- (NSString *)name {
if (_name == nil) {
_name = @"XXX";
}
return _name;
}
在Swift中可以使用!和?来表示一个对象是optional的还是non-optional,如button?和button!。而在Objective-C中则没有这一区分。这个简版的 Optional ,没有 Swift 中 ? 和 ! 语法糖的支持,在 Objective-C 中就显得非常啰嗦,所以为了防止写一大堆 nonnull,Foundation 还提供了一对宏,包在里面的对象默认加 nonnull 修饰符,只需要把 nullable 的指出来就行,黑话叫 Audited Regions:
NS_ASSUME_NONNULL_BEGIN
@interface Sark : NSObject
@property (nonatomic, copy, nullable) NSString *workingCompany;
@property (nonatomic, copy) NSArray *friends;
- (nullable NSString *)gayFriend;
@end
NS_ASSUME_NONNULL_END
不过,为了安全起见,苹果还制定了几条规则:
- typedef定义的类型的nullability特性通常依赖于上下文,即使是在Audited Regions中,也不能假定它为nonnull。
- 复杂的指针类型(如id *)必须显示去指定是nonnull还是nullable。例如,指定一个指向nullable对象的nonnull指针,可以使用”__nullable id * __nonnull”。
- 我们经常使用的NSError **通常是被假定为一个指向nullable NSError对象的nullable指针。
参考文章:
2015 Objective-C 新特性
OC