ios 你必须了解的系统定义宏使用

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;
}

 

posted @ 2017-07-24 11:57  _水畔竹汐  阅读(1260)  评论(0编辑  收藏  举报