iOS的指定初始化:使用NS_DESIGNATED_INITIALIZER

问题描述:

我们这个新的宏被XCode中6介绍:NS_DESIGNATED_INITIALIZERiOS的指定初始化:使用NS_DESIGNATED_INITIALIZER

我在网上搜索,但不能真正找到任何好的文档,至于怎么用这个。

在语法上,我们可以用它喜欢:

- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; 

但什么是标有这个宏的初始值的可能的优势,也是我们应该寻找的东西用这个当?

我主要感兴趣的是这个宏的用例。任何链接/文件将不胜感激。

采用NS_DESIGNATED_INITIALIZER是很好在http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html解释:

The designated initializer guarantees the object is fully initialised by sending an initialization message to the superclass. The implementation detail becomes important to a user of the class when they subclass it. The rules for designated initializers in detail:

  • A designated initializer must call (via super) a designated initializer of the superclass. Where NSObject is the superclass this is just [super init].
  • Any convenience initializer must call another initializer in the class - which eventually leads to a designated initializer.
  • A class with designated initializers must implement all of the designated initializers of the superclass.

作为一个例子,如果接口是

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

斯威夫特的有关规定确定的和方便的初始化是更严格, 如果你混的Objective-C和斯威夫特代码,标志着指定目标-C初始化器帮助编译器执行规则。

例如,这斯威夫特子类会导致编译器错误:

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: "") 
    } 
} 
+2

Objective-C中的概念并不是很好的想法,因为'initWithName:@“”'在进行子类化时并不总是有意义的。相反,通常从超类中重写的指定初始化器应该抛出异常,说使用来自子类的指定初始化器。 – Andy 2015-10-18 15:47:23

+5

要添加到Martin的答案,您可能想要完全禁止用户调用默认的初始化程序,在这种情况下,您可以使用以下内容: - (instancetype)init NS_UNAVAILABLE; – 2016-02-18 16:21:28

指定的初始定义我们如何继承结构时,我们的初始化;他们是你的班级的“规范初始化者”。无论您调用超类链中的哪个指定初始值设定项,它都保证可靠,并始终从最远的祖先到最远的后代。

指定的初始化程序未定义创建对象时应使用的初始化程序。这在https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns中有详细解释。

我最常用的方式做到这一点:

@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_INITIALIZERNSObjectinit:在这种情况下) - 我们使用NS_UNAVAILABLE将此方法标记为不需要。或者您可以覆盖它以使用默认参数调用指定的初始化程序。