16

MyClassクラスがあります。インスタンス変数passedInVar1、passedInVar2などがあり、その値は初期化を要求するオブジェクトから渡されます。また、アーカイブからデコードされるインスタンス変数decodeVar1、decodeVar2などがあります。アーカイブがない場合はデフォルト値に設定されます。

Appleによると、

オブジェクトがinitWithCoder:メッセージを受信すると、オブジェクトは最初にメッセージをスーパークラスに送信して(適切な場合)、継承されたインスタンス変数を初期化し、次に自身のインスタンス変数をデコードして初期化する必要があります。

しかし、Appleはまた、クラスには単一の指定された初期化子が必要であると述べています。

これらすべてに対処するための最良の方法は何ですか?

4

1 に答える 1

28

アップルズは次のように述べています。

指定イニシャライザ クラスの新しいインスタンスを初期化する主な役割を持つ init... メソッド。各クラスは、独自の指定された初期化子を定義または継承します。自分自身へのメッセージを通じて、同じクラス内の他の init... メソッドが指定された初期化子を直接的または間接的に呼び出し、指定された初期化子は、スーパーへのメッセージを通じて、そのスーパークラスの指定された初期化子を呼び出します。[従業員追加]

原則として、指定された初期化子は、他のすべての init メソッドが呼び出す 1 つの init メソッドです。ただし、init メソッドはこれだけではありません。また、各クラスが独自のものである必要もありません。多くの場合、指定された初期化子は実際にはスーパークラスの init です。

の主な機能はinitWithCoder、アーカイブされたオブジェクトからの初期化を可能にすることです。特定のデータを必要とするクラスの場合、指定された初期化子がそのデータを受け入れます。initWithCoder次に、単にアーカイブを解凍し、指定されたイニシャライザを呼び出します。

たとえば、UIView の指定された初期化子は ですinitWithFrame:。したがって、UIView は次のinitWithCoderようになります。

- (id)initWithCoder:(NSCoder *)decoder{
    CGRect theFrame= //...uppack frame data
    self=[self initWithFrame:theFrame];
    return self;
}

指定イニシャライザのポイントは、データの取得元や初期化の状況に関係なく、各インスタンスが完全に初期化されるようにするために、すべての初期化が通過する必要がある中心点を作成することです。

これは、クラスがイニシャライザ メソッドを 1 つしか持てないことを意味するものではありません。

Edit01

コメントから:

特に、initWithCoder を介して初期化が行われているときに、一部の ivar に値を渡すにはどうすればよいですか?

まあ、あなたはしません。initWithCoder の全体的なポイントは、オブジェクトを再作成するために必要なすべてのデータを含むクラスの凍結乾燥インスタンスを扱っているということです。

NSCoding プロトコルにより、クラスはコミックで「Sea Monkeys」として販売されているブラインシュリンプのように動作します。コーディング方法は、ブラインシュリンプ/インスタンスを脱水/凍結乾燥します。デコード方法は、ブラインシュリンプを水に注ぐのと同じように、ブラインシュリンプ/インスタンスを水和します。ブラインシュリンプが水を除いて生活を始めるために必要なものをすべて持っているように、ディスクに保存されたコード化されたオブジェクトは、コーダーで初期化されると、それ自体を再作成するために必要なすべてのデータを持っています。

これの標準的な例は nib ファイルです。nib ファイルは、UI 要素とコントローラーのフリーズドライされたインスタンスの集まりです。nib 内の UIViewController とその UIView には、nib ファイルの xml にコード化された初期化に必要なすべてのデータがあります。initFromNib直接または IBOutlet を使用して呼び出すと、各クラスのメソッドintiWithCoder:が呼び出されます。

オブジェクトをフリーズドライするときに完全なオブジェクトを保存しない場合、インスタンス オブジェクトが存在するためにフリーズドライされない属性は必要ありません。

オブジェクトが初期化された後、これらの補助属性を設定するだけです。

指定イニシャライザをインライン化するには、最初にデコードしてから、指定イニシャライザを呼び出します。そのようです:

-(id) initWithRequiredValue:(id) someValue otherRequiredValue:(id) anotherValue{
    if (self=[super init]){
        self.requiredProperty=someValue;
        self.anotherRequiredProperty=anotherValue
    }
    return self;
}

スーパークラスが NSCoder をサポートしていない場合は、サブクラスで自分で開始します。

- (id)initWithCoder:(NSCoder *)decoder {
    id someDecodedValue=[decoder decodeObjectForKey:@"someValueKey"];
    id someOtherDecodedValue=[decoder decodeObjectForKey:@"someOtherValueKey"];
    self=[self initWithRequiredValue:someDecodedValue otherRequiredValue:someOtherDecodedValue];
    return self;
}

それが最も単純なケースです。super 自体が NSCoding をサポートしている場合、通常は、次のように並列指定イニシャライザを記述するだけです。

- (id)initWithCoder:(NSCoder *)decoder {
    if (self=[super initWithCoder:decoder]){
        id someDecodedValue=[decoder decodeObjectForKey:@"someValueKey"];
        id someOtherDecodedValue=[decoder decodeObjectForKey:@"someOtherValueKey"];
        self.requiredProperty=someDecodedValue;
        self.anotherRequiredProperty=someOtherDecodedValue;
    }
    return self;
}

ほとんどの場合、initWithCoder指定された初期化子と同じようにすべての初期化を処理するため、最終的に並列指定された初期化子になると思います。すべてのデータがコーダーによって提供されるため、指定された初期化子のようには見えませんが、同じ機能を実行します。

これは、理論と実践がうまく一致しないケースの 1 つです。「指定されたイニシャライザ」の概念は、インスタンスを最初から作成する場合にのみ適用されます。

于 2010-05-31T17:06:30.270 に答える