2014-01-18 8 views
5

メソッドの中にif (self == SomeClass class)を含める必要がある理由を説明できる人はいますか?-initと+ initializeの実装

私は(下記参照)と同様の質問を見つけましたが、見つかりませんでした任意の特定の明確化:

  1. Objective-C: init vs initialize
  2. Should +initialize/+load always start with an: if (self == [MyClass class]) guard?

誰もがあなたが実装していない場合と言います/ Subclassの+initializeをオーバーライドすると、親クラスを2回呼び出すことになります。

誰もが特にその部分を説明することはできますか?具体的には、なぜ親クラスを2回呼び出すのですか?

最後に、私たちがカスタム-initメソッドを作成し、self = [super init];を呼び出すNSObjectから継承するクラスに+initializeを実装すると、どうして起こりませんか?

+0

initとinitializeはお互いに関係ありません。 – rmaddy

+0

@rmaddy '-init'の中に' self = [super init]; 'があり、これは親の' + initialize'を呼びますか? – makaed

+1

あなたは正しくありません。初期化は、他のクラスまたはインスタンスメソッドが呼び出される前にクラスごとに1回呼び出されます。 – rmaddy

答えて

4

-initおよび+initializeは全く異なるものです。最初はインスタンスを初期化するためのものです。 2番目はクラスを初期化するためのものです。

どのクラスにもメッセージが初めて送信されると、ランタイムは+initializeとそのスーパークラスに必ず呼び出します。スーパークラスは、どのサブクラスも自身を初期化する前に準備が必要であるため、最初に初期化されます。その時YourSubclassがメッセージとして送られるので、最初

、のような何かを行う可能性がありますランタイムは:それはおそらく、これはNSObjectがメッセージとして送られるのは初めてだろうと非常に低いですので、ものの

[NSObject initialize]; 
[YourClass initialize]; 
[YourSubclass initialize]; 

(それはdoesnのトンこの時点で初期化する必要があります。それはちょうど、説明のためです。)

YourSubclass+initializeを実装していない場合は、上記のよう[YourSubclass initialize]の呼び出しは、実際に+[YourClass initialize]を呼び出します。それは仕事での通常の継承メカニズムです。それは+[YourClass initialize]が呼び出された2回目になります。

+initializeの方法で行われた作業は、通常は一度だけ行うべきものなので、ガードif (self == [TheClassWhoseImplementationThisMethodIsPartOf class])が必要です。また、その作業では、多くの場合、書かれている現在のクラスを参照すると仮定しているため、ガードの理由にもなります。

2番目の答えは、+setKeys:triggerChangeNotificationsForDependentKey:メソッドでKVO依存キーを登録する旧式のメカニズムである例外を示しています。このメソッドは、サブクラスではなく、呼び出された実際のクラスに固有です。あなたはそれを避け、最新の+keyPathsForValuesAffectingValueForKey:または+keyPathsForValuesAffecting<Key>メソッドを使用する必要があります。古い方法を使用する必要がある場合は、その部分をガードの外に置きます。また、そのようなクラスのサブクラスは、通常行われていないsuperにコールスルーする必要があります。

更新:ランタイムがすでにスーパークラスを初期化しているため、

+initialize方法は、通常superに通じ呼び出すべきではありません。スーパークラスが古いメカニズムを使用して従属キーを登録することがわかっている場合にのみ、すべてのサブクラスはスーパーにコールスルーする必要があります。

-initの場合、ランタイムはあなたの呼び出し前に自動的にスーパークラスのinitメソッドを呼び出すわけではないので、同じ心配はありません。実際に、initメソッドがsuperにコールしない場合、インスタンスのスーパークラスの「一部」は何も初期化されません。

+0

あなたの例の 'TheClassWhoseImplementationThisMethodIsPartOf'は' YourClass'でしょうか? – makaed

+1

'+ [YourClass initialize]'の実装の中では、そうです。私はそれを一般的にしようとしました。 –

0

あなたの質問には良い回答があります。要約すると、すべてのクラスでランタイムによって+initializeが呼び出されるため、N個のサブクラスを持つスーパークラスの場合は、スーパークラスでN + 1回呼び出されます(直接的に1回、継承するサブクラスごとに1回)。サブクラスがそれをオーバーライドしてsuperを呼び出すのと同じことです。

スーパークラスのレベルで "これは私の直接の初期化であり、スーパークラスは継承またはサブクラスによって呼び出されませんか?

if (self == [ThisSuperclass self]) {} 

-initクラスのインスタンスを初期化するために使用され、+initializeなどのデフォルトでは、ランタイムによって呼び出されていません。インスタンスは、-initの実装を継承し、継承された実装をオーバーライドすることができ、また継承された実装の利点を[super init];と呼ぶことで楽しむことができます。

+0

'+ initialize'は、コードなしでランタイムによって呼び出されます。はいの場合、スーパークラスの中でサブクラスの中で呼び出されたときに '+ initialize'をどのような場合に行うのでしょうか? – makaed

+1

@danhの場合、サブクラスが 'super'を呼び出してメソッドが2回呼び出されるだけではありません。また、サブクラスが '+ initialize'を実装していない場合もありますが、これははるかに一般的な状況です。 –

+0

私は参照してください。ありがとう、私は編集しました。 – danh

5

+initializeを実装するスーパークラスとそうでないサブクラスがあるとします。

@interface SuperClass : NSObject @end 
@implementation SuperClass 
+(void)initialize { 
    NSLog(@"This is class %@ running SuperClass +initialize", self); 
} 
@end 

@interface SubClass : SuperClass @end 
@implementation SubClass 
// no +initialize implementation 
@end 

スーパークラスを使用してください。これにより、+[SuperClass initialize]への呼び出しが呼び出されます。

[SuperClass class]; 
=> This is class SuperClass running SuperClass +initialize 

ここでサブクラスを使用します。ランタイムは+initializeの実装を​​に探し、何も見つかりません。次に、継承された実装をSuperClassに探し、見つけます。継承された実装は、それがすでにSuperClass自体に代わって、一度呼ばれていたにも関わらず呼び出されます:

[SubClass class]; 
=> This is class SubClass running SuperClass +initialize 

ガードは、あなたが、最高1回実行されなければならない作業を行うことができます。それ以降の呼び出しでは、+initializeにはselfと異なるクラスが存在するため、ガードはそれらを無視できます。