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

Meh*_*mar 35 xcode initialization objective-c ios xcode6

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

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

从语法上讲,我们可以使用它:

- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
Run Code Online (Sandbox Code Playgroud)

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

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

Mar*_*n R 55

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

指定的初始化程序通过向超类发送初始化消息来保证对象完全初始化.实现细节在类的用户子类化时变得很重要.指定初始化程序的规则详细说明:

  • 指定的初始化程序必须调用(通过super)超类的指定初始化程序.其中NSObject是超类,这只是[super init].
  • 任何便利初始化程序必须调用类中的另一个初始化程序 - 最终会导致指定的初始化程序.
  • 具有指定初始值设定项的类必须实现超类的所有指定初始值设定项.

例如,如果您的界面是

@interface MyClass : NSObject
@property(copy, nonatomic) NSString *name;
-(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;
-(instancetype)init;
@end
Run Code Online (Sandbox Code Playgroud)

然后编译器检查(方便)初始化程序是否init调用(指定的)初始化程序initWithName:,因此这将导致警告:

-(instancetype)init
{
    self = [super init];
    return self;
}
Run Code Online (Sandbox Code Playgroud)

这没关系:

-(instancetype)init
{
    self = [self initWithName:@""];
    return self;
}
Run Code Online (Sandbox Code Playgroud)

Swift中,关于指定和便利初始化器的规则甚至更严格,如果混合使用Objective-C和Swift代码,标记指定的Objective-C初始化器有助于编译器强制执行规则.

例如,此Swift子类将导致编译器错误:

class SwClass: MyClass {
    var foo : String
    init(foo : String) {
        self.foo = foo
        super.init()
    }
}
Run Code Online (Sandbox Code Playgroud)

这没关系:

class SwClass: MyClass {
    var foo : String
    init(foo : String) {
        self.foo = foo
        super.init(name: "")
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 要添加到Martin的答案,您可能希望完全禁止用户调用默认初始化程序,在这种情况下,您可以使用以下内容: - (instancetype)init NS_UNAVAILABLE; (5认同)
  • 在Objective-C中通过概念没有深思熟虑,因为`initWithName:@""`在子类化时并不总是有意义.相反,通常从超类重写指定的初始化程序应该抛出异常,说从子类使用指定的初始化程序. (2认同)

Tim*_*ich 12

我最常见的方法是:

@interface Person : NSObject

- (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)init NS_UNAVAILABLE;

@property (nonatomic, nonnull) NSString *name;

@end
Run Code Online (Sandbox Code Playgroud)

并实施

@implementation Person

- (instancetype)initWithName:(NSString *)name
{
    self = [super init];
    if (self) {
        self.name = name;
    }
    return self;
}

@end
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你不应该重写NS_DESIGNATED_INITIALIZER超类方法(的NSObjectinit:在这种情况下) -我们用来NS_UNAVAILABLE标记该方法不需要.或者您可以覆盖它以使用默认参数调用指定的初始化程序.