iOS指定的初始化程序:使用NS_DESIGNATED_INITIALIZER
我们在XCode 6中引入了这个新的macros:NS_DESIGNATED_INITIALIZER
我在网上search,但无法find任何有关如何使用它的好文档。
在语法上,我们可以像这样使用它:
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
但是用这个macros标记一个初始值设定项有什么好处,而且在使用这个macros时我们应该注意些什么呢?
我主要感兴趣的是这个macros的用例。 任何链接/文件将不胜感激。
NS_DESIGNATED_INITIALIZER
的使用在http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html中有很好的解释:
指定的初始化程序保证通过向超类发送初始化消息来完全初始化对象。 实现细节在对类的用户进行子类化时变得重要。 指定初始值设定项的细则如下:
- 指定的初始化程序必须(通过超级)调用超类的指定初始化程序。 NSObject是超类,这只是[超级初始化]。
- 任何便利初始值设定项都必须调用该类中的另一个初始值设定项 – 最终导致指定的初始值设定项。
- 具有指定初始化器的类必须实现超类的所有指定初始化器。
举个例子,如果你的界面是
@interface MyClass : NSObject @property(copy, nonatomic) NSString *name; -(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER; -(instancetype)init; @end
那么编译器会检查(便利)初始化程序init
调用(指定的)初始化程序initWithName:
,所以这会引起一个警告:
-(instancetype)init { self = [super init]; return self; }
这将是确定的:
-(instancetype)init { self = [self initWithName:@""]; return self; }
在Swift中 ,有关指定和便捷初始值设定项的规则更加严格,如果混合使用Objective-C和Swift代码,则标记指定的Objective-C初始值设定项有助于编译器执行规则。
例如,这个Swift子类会导致编译器错误:
class SwClass: MyClass { var foo : String init(foo : String) { self.foo = foo super.init() } }
这将是确定的:
class SwClass: MyClass { var foo : String init(foo : String) { self.foo = foo super.init(name: "") } }
我最常见的做法是:
@interface Person : NSObject - (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER; - (nullable instancetype)init NS_UNAVAILABLE; @property (nonatomic, nonnull) NSString *name; @end
并执行
@implementation Person - (instancetype)initWithName:(NSString *)name { self = [super init]; if (self) { self.name = name; } return self; } @end
在这种情况下,您不应该重写超类方法的NS_DESIGNATED_INITIALIZER
( NSObject
的init:
在这种情况下) – 我们使用NS_UNAVAILABLE
来将此方法标记为不需要。 或者你可以覆盖它来使用默认参数调用你指定的初始值设定项。
指定的初始化器定义了子类化时我们如何构造初始化器; 他们是你的class级的“规范初始化者”。 它保证是可靠的,不pipe在你调用的超类链中哪个指定的初始化方法,并且总是从最远的祖先到最远的后代。
指定的初始化程序没有定义创build对象时应使用的初始化程序。 这在https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns中解释过。