Objective-C的初始化方法总结


 

分析:

OC中对象的init方法有两种: 指定初始化器(Designated Initializers )、便利初始化器(Convenience Initializers) Designated Initializers能保证初始化所有需要初始化的数据,RD需要自己保证,可能有多个不同方法,代表从不同源/不同方式进行初始化,比如UIView就有initWithFrame和initWithNib分别代表从代码和Nib初始化。 Convenience Initializers字面意思便利初始化,它内部一定会调用Designated Initializers 总结:所有的初始化方法的根本都是调用Designated Initializers。   那么如何告诉编译器某个方法是Designated Initializers呢? NS_DESIGNATED_INITIALIZER 这是个宏,含义就是一个编译器指令,告诉编译器这个是指定初始化方法 #ifndef NS_DESIGNATED_INITIALIZER #if __has_attribute(objc_designated_initializer) #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) #else #define NS_DESIGNATED_INITIALIZER #endif #endif 举个??,一个ViewController,继承于UIViewController: #import   @interface ViewController : UIViewController   // 我自己定义的init方法,我希望ViewController这个类初始化只能用这个方法 - (instancetype)initWithSomething NS_DESIGNATED_INITIALIZER;   @end 在.h里我声明了initWithSomething方法,并且指定了NS_DESIGNATED_INITIALIZER宏。   OC有几条规定:
  1. 子类的Designated Initializers必须调用父类的Designated Initializers
  2. 子类如果声明了新的Designated Initializers方法,那么有两种方案:
2a. 要在子类中复写父类的所有Designated Initializers,内部都导向到子类新的Designated Initializers方法去。 2b. 在子类中直接禁用父类其它的Designated Initializers,使用NS_UNAVAILABLE这个宏。   分析一下为啥要这么规定: 对于上面的1:如果不强制子类的Designated Initializers内部调用父类的Designated Initializers,那么子类的Designated Initializers有可能只调用了父类的某个Convenience Initializers,而Convenience Initializers无法保证初始化父类所有的成员变量!所以Apple官方从源头上进行遏制。 对于2也是类似的:因为子类中依然可以调用父类的任意Designated Initializers方法,比如上面的自定义ViewController类,如果我这样调用父类UIViewController的Designated Initializers方法: [ViewController alloc] initWithNibName:xx bundle:yy] 那么显然子类ViewController中的成员变量没有进行初始化,这是不能接受的。   分析的透彻一点,子类一旦声明了新的Designated Initializers方法,那么父类的Designated Initializers方法其实就相当于“退化”了,因为它们无法保证初始化子类的所有成员变量,已经无法满足“初始化方法”的定义。而如果你仍想继续使用父类的某些Designated Initializers方法,你就复写,并且在其内部调用到新的Designated Initializers方法;而如果你不想再用父类的某些Designated Initializers方法了,那更简单,在子类.h里直接禁用它们。  

最终实现:

ViewController.h: @interface ViewController : UIViewController // init是NSObject的初始化方法,我不想让别人用,在.h里直接禁用 - (instancetype)init NS_UNAVAILABLE; // 这个initWithNibName方法是UIViewController的,我也不想让别人用,禁用 - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil NS_UNAVAILABLE; // 我自己定义的Designated Initializers方法 - (instancetype)initWithSomething NS_DESIGNATED_INITIALIZER;   @end ViewController.m: @implementation ViewController   #pragma mark - Designated Initializers // 唯一Designated Initializers - (instancetype)initWithSomething { // 注意:这里调用了父类的Designated Initializers:initWithNibName方法 self = [super initWithNibName:nil bundle:nil]; if (self) { self.view.backgroundColor = UIColor.whiteColor; } return self; }   #pragma mark - Convenience Initializers // 这个initWithCoder方法我还想用,那么复写,在内部调用initWithSomething即可 - (instancetype)initWithCoder:(NSCoder *)coder { return [self initWithSomething]; } 对于上面的ViewController类,Designated Initializers方法只有一个:initWithSomething Convenience Initializers方法也是一个:initWithCoder
OC