1. UNAVAILABLE_ATTRIBUTE __attribute__((unavailable))
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
告诉编译器该方法不可用,如果强行调用编译器会提示错误。比如某个类在构造的时候不想直接通过init来初始化,只能通过特定的初始化方法()比如单例,就可以将init方法标记为unavailable;
效果如下:
调用了会有警告
2. NS_ASSUME_NONNULL_BEGIN , NS_ASSUME_NONNULL_END
如果需要每个属性或每个方法都去指定nonnull和nullable,是一件非常繁琐的事。苹果为了减轻我们的工作量,专门提供了两个宏:NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END。在这两个宏之间的代码,所有简单指针对象都被假定为nonnull,因此我们只需要去指定那些nullable的指针
- nonnull作用:不能为空
使用方法
NS_ASSUME_NONNULL_BEGIN @interface TestNullabilityClass () @property (nonatomic, copy) NSArray * items; - (id)itemWithName:(nullable NSString *)name; @end NS_ASSUME_NONNULL_END
在上面的代码中,items属性默认是nonnull的,itemWithName:方法的返回值也是nonnull,而参数是指定为nullable的。
不过,为了安全起见,苹果还制定了几条规则:
- typedef定义的类型的nullability特性通常依赖于上下文,即使是在Audited Regions中,也不能假定它为nonnull。
- 复杂的指针类型(如id *)必须显示去指定是nonnull还是nullable。例如,指定一个指向nullable对象的nonnull指针,可以使用”__nullable id * __nonnull”。
- 我们经常使用的NSError **通常是被假定为一个指向nullable NSError对象的nullable指针。
3. NS_DESIGNATED_INITIALIZER
Objective-C 中主要通过NS_DESIGNATED_INITIALIZER
宏来实现指定构造器的。这里之所以要用这个宏,往往是想告诉调用者要用这个方法去初始化(构造)类对象。
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) - (instancetype)init; - (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;
/* init是 convenience initializer方法只是简单的调用initWithName:(指定初始化器),并设置一个默认值。initWithName:进行完整的初始化并调用父类的init方法。 指定初始化器有以下几个规则: 1.指定初始化器方法必须调用父类的指定初始化器方法,如果父类为NSObject时调用 [super init]。 2.convenience initializer方法必须调用其他的初始化方法,知道最后指向指定初始化 器方法。 3.一个类如果有指定初始化器方法,那么就必须实现所有父类的指定初始化器方法。 */ - (instancetype)init { return [self initWithName:@"Unknown"]; } - (instancetype)initWithName:(NSString *)name { self = [super init]; if (self) { _name = [name copy]; } return self; }