0

Parent.h (NSObject を拡張) は次のようになります。

@implementation InTParent

-(id)init
{
    NSLog(@"Parent init method");
    if (self = [super init]) {
        ;
    }
    return self;
}


-(id)initWithName:(NSString*)name;
{
    NSLog(@"Parent initWithName method");
    if (self = [self init]) {
        ;
    } 
    return self;
}

Son.h(親を拡張)は次のようになります:

@implementation InTSon

-(id)init
{
    NSLog(@"Son init method");
    if (self = [super init]) {
        ;
    }
    return self;
}

-(id)initWithName:(NSString*)name;
{
    NSLog(@"Son initWithName method");
    if (self = [super initWithName:name]) {
        ;
    }
    return self;
}

私はこれを使用します:IntSon *_son = [[IntSon alloc] initWithName:@"asd"];

出力が次のようになる理由: Son initWithName メソッド --> 親 initWithName メソッド --> Son init メソッド --> 親 init メソッド

しかし Java では、おそらく次のようになります: Son initWithName メソッド --> 親 initWithName メソッド --> 親 init メソッド

私を助けてください!

4

3 に答える 3

2

この動作を理解するには、Objective-C メッセージのディスパッチがどのように機能するかを理解する必要があります。そして、これはそれを説明する良い例です。

大まかに言うと、任意のオブジェクトでメソッドを呼び出すたびに、Objective-C ランタイムは、最も派生した (クラス階層で最も深い) クラスを提供する実装を探します。見つからない場合は、次の最も派生したものに移動し、NSObject. セレクター (大まかなメソッド名) に一致する実装が初めて見つかったときに、その実装を実行します。を呼び出すときはsuper、そのメソッドの次の派生クラスの実装にメッセージを送信するように指定しています。

したがって、コードではalloc、クラスを呼び出します。これは、クラス object に設定されたポインターを使用してInTSonのインスタンスを返します。ポインターは、クラス階層を昇るプロセス中にメソッドの実装がどのように検索されるかです。IntSonisaInTSonisa

したがって、InTSonインスタンスを取得した後、それを呼び出すinitWithName:と、が指すクラスがチェックされますisa(これはInTSon、このメソッドの実装用です。それを見つけて実行すると、最初の出力が得られます。

"Son initWithName method"

その直後に、そのメソッドのスーパークラス実装を呼び出します。これにより、そのコードInTParentの実装が検索されてinitWithName:実行され、2 番目の出力が得られます。

Parent initWithName method

ここで、Java からの逸脱が見られinitますselfselfただし、InTSonインスタンスへのポインタです。そのため、ランタイムがこのメッセージを解決するとき、最初にクラスinit内のの実装を探します。InTSonもちろん、それを見つけてそのメソッドのコードを実行すると、3 番目の出力 が得られますSon init methodInTParent次に、 の実装を参照して実行する super を呼び出しinit、最終的な出力を提供します。

要約すると、クラス階層のどこからメソッドが呼び出されたかに関係なく、 on で呼び出された場合、そのメソッドの最も派生した実装self常に実行されます。ご不明な点がございましたら、お気軽にお問い合わせください。

于 2012-09-07T03:03:20.760 に答える
1

クラス図は次のようになります。

クラス図

initWithName:メッセージを のインスタンスに送信するInTSonと、システムはInTSonのメソッド テーブルでメソッドを検索し、呼び出すメソッドを見つけます-[InTSon initWithName:]。その方法を単純化すると、次のようになります。

// -[InTSon initWithName:]
- (id)initWithName:(NSString *)name {
    return [super initWithName:name];
}

このメソッドは[super initWithName:name]. メッセージを に送信するためsuper、システムは のクラスのスーパークラスのメソッド テーブルを調べますself。オブジェクトのクラスはInTSonで、そのスーパークラスはInTParentです。そのため、-[InTSon initWithName:]が実行[super initWithName:name]されると、システムはInTParentのメソッド テーブルでメソッドを検索します。呼び出すメソッドを見つけます-[InTParent initWithName:]。その方法を単純化すると、次のようになります。

// -[InTParent initWithName:]
- (id)initWithName:(NSString *)name {
    return [self init];
}

このメソッドは[self init]. メッセージは に送信されるためself、システムはメソッド テーブルでselfのクラスを検索します。に入っていますが-[InTParent initWithName:]selfはまだInTSonクラスのインスタンスです。したがって、システムはのメソッド テーブルinitでメソッドを探します。InTSon呼び出すメソッドを見つけます-[InTSon init]。その方法を単純化すると、次のようになります。

// -[InTSon init]
- (id)init {
    return [super initWithName:@"sdas"];
}

この[super initWithName:]メソッドInTParent-[InTParent initWithName:]. 先ほど見-[InTParent initWithName:]たように、 は を呼び出し[InTSon init]ます。そのため、無限再帰が発生し、アプリがクラッシュします。

この問題を解決するには、InTParentの init メソッドの1 つを指定された初期化子として選択する必要があります。 Apple のドキュメントで指定された初期化子について読む必要があります。

の指定された初期化子initWithName:としてメソッドを選択する必要があります。InTParentこのメソッドは、init メッセージを に送信してはなりませself。スーパーの指定されたイニシャライザ メッセージ (の場合はメッセージ)のみを送信する必要があり、それを に送信する必要があります。したがって、次のようにメソッドを記述する必要があります。NSObjectinitsuper-[InTParent initWithName:]

- (id)initWithName:(NSString *)name {
    // init is NSObject's designated initializer, and we send it to super.
    if ((self = [super init])) {
        // your initialization code here
    }
    return self;
}

指定イニシャライザを選択し、指定イニシャライザがスーパークラスの指定イニシャライザ メッセージのみを に送信するsuperようにすることで、無限再帰を防止できます。

于 2012-09-07T03:16:17.960 に答える
0

「self」は「InTSon」なので、[self init] は「InTSon」の init メソッドを呼び出します。

于 2012-09-07T02:54:16.690 に答える