iOS指定的初始化程序:使用NS_DESIGNATED_INITIALIZER

时间:2014-10-03 19:08:45

标签: ios objective-c xcode initialization xcode6

我们在XCode 6中引入了这个新宏:NS_DESIGNATED_INITIALIZER

我在网上搜索,但无法找到任何关于如何使用它的好文档。

从语法上讲,我们可以像:

一样使用它
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

但是使用这个宏标记初始化程序有什么可能的优点,以及使用它时我们应该注意什么?

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

3 个答案:

答案 0 :(得分:51)

http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html中很好地解释了NS_DESIGNATED_INITIALIZER的使用:

  

指定的初始化程序保证对象完全初始化   通过向超类发送初始化消息。该   实现细节对于类的用户来说变得很重要   他们将它分类。指定初始化程序的规则详细说明:

     
      
  • 指定的初始化程序必须调用(通过super)指定的   超类的初始化程序。其中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: "")
    }
}

答案 1 :(得分:12)

我最常用的方法是:

@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的{​​{1}}) - 我们使用init:将此方法标记为不需要。或者您可以覆盖它以使用默认参数调用指定的初始化程序。

答案 2 :(得分:1)

指定的初始化器定义了在子类化时我们如何构造初始化器;它们是您班级的“规范初始化者”。无论您调用的超类链中指定的初始化程序如何,它都保证可靠,并且始终从最远的祖先到最远的后代。

指定的初始值设定项未定义创建对象时应使用的初始值设定项。它在https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns中得到了很好的解释。