web-dev-qa-db-ja.com

iOS指定イニシャライザー:NS_DESIGNATED_INITIALIZERの使用

この新しいマクロがXCode 6で導入されています:NS_DESIGNATED_INITIALIZER

私はネット上で検索しましたが、これを使用する方法に関して良いドキュメントを見つけることができませんでした。

構文的には、次のように使用できます。

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

しかし、このマクロでイニシャライザーをマークすることの可能な利点は何ですか?また、これを使用する際に注意すべきことは何ですか?

私は主にこのマクロのユースケースに興味があります。リンク/ドキュメントをいただければ幸いです。

34
Mehul Parmar

の用法 NS_DESIGNATED_INITIALIZERhttp://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html でうまく説明されています。

指定された初期化子は、初期化メッセージをスーパークラスに送信することにより、オブジェクトが完全に初期化されることを保証します。実装の詳細は、クラスのユーザーがサブクラス化するときに重要になります。指定された初期化子のルールの詳細:

  • 指定された初期化子は、スーパークラスの指定された初期化子を(スーパー経由で)呼び出す必要があります。 NSObjectがスーパークラスである場合、これは単に[super init]です。
  • 便利なイニシャライザは、クラス内の別のイニシャライザを呼び出す必要があります-最終的には指定されたイニシャライザにつながります。
  • 指定された初期化子を持つクラスは、スーパークラスの指定されたすべての初期化子を実装する必要があります。

例として、インターフェースが

@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: "")
    }
}
55
Martin R

これを行う最も一般的な方法:

@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(この場合はNSObjectinit:)をオーバーライドしないでください。このメソッドを不要としてマークするためにNS_UNAVAILABLEを使用しました。または、これをオーバーライドして、指定された初期化子をデフォルトのパラメーターで呼び出すことができます。

12

指定された初期化子は、サブクラス化する際の初期化子の構造を定義します。これらは、クラスの「標準的な初期化子」です。呼び出すスーパークラスチェーン内の指定された初期化子に関係なく、信頼できることが保証され、常に最も遠い祖先から最も遠い子孫に移動します。

指定された初期化子は、オブジェクトの作成時に使用する初期化子を定義しません。 https://blog.Twitter.com/2014/how-to-objective-c-initializer-patterns で非常に説明されています。

1
larva