2

I have heard that when you have a subclass, you are supposed to initialize the superclass with the same init function from within the subclass's init. What I mean is that the subclass's init should call [super init] and the subclass's initWithFrame should call [super initWithFrame]. Why is this? Why does calling the super's init from a subclass's initWithFrame result in an infinite loop?

If this is required, then does this mean I can't create a new init function within a subclass such as initWithPoint and have that call super's init or initWithFrame simply because the super class doesn't have initWithPoint? I guess the heart of the question here is simply why it's improper to call a different super class, something that's confusing me possibly because of my c++ background?

4

5 に答える 5

3

どうしてこれなの?サブクラスのinitWithFrameからスーパーのinitを呼び出すと、無限ループが発生するのはなぜですか?

insuper-initが次のように実装されている場合

-(id)init {
  return [self initWithFrame:CGRectZero];
}

次に、コールグラフがループします。

[subclass initWithFrame:]
   |     ^
   v     |
[super init]

いつものようselfに現在のクラス(「サブクラス」)を使用します。


これが必要な場合、これは、スーパークラスにinitWithPointがないという理由だけで、initWithPointなどのサブクラス内に新しいinit関数を作成できず、スーパーのinitまたはinitWithFrameを呼び出すことができないことを意味しますか?

いいえ、これは必須ではありません。推奨されるのは、superの最も特殊な初期化子を呼び出す-initXXXことです。そのため、superがサブクラスのを呼び出す可能性はありません-initYYY

于 2010-10-23T07:21:18.890 に答える
3

サブクラスを作成するとき、イニシャライザを実装する場合は、スーパークラスの指定されたイニシャライザを必ず呼び出す必要があり、独自の指定されたイニシャライザを少なくとも 1 つ提供する必要があります。 .

サブクラスの初期化の一環として、スーパークラスの指定された初期化子の 1 つを呼び出す必要があります。

クラスのドキュメントでは、指定された初期化子を指定する必要があります。そうでない場合、指定された初期化子は通常、スーパークラスによって提供される最も具体的な初期化子 (最も多くの引数を取るもの) であると見なされます。

詳細については、「Objective-C プログラミング言語: オブジェクトの割り当てと初期化」を参照してください。 [注: 2013 年 12 月の時点で、このコンテンツは Apple のドキュメント センターから入手できなくなったようです。言語リファレンスだったものは、よりタスク指向のチュートリアルと概念的なドキュメントに置き換えられました。]

具体的な質問について:

どうしてこれなの?スーパークラスがその状態を初期化する機会があるように。次に、スーパークラスが提供するものを超えて、追加した状態を初期化できます。

サブクラスの initWithFrame からスーパーの init を呼び出すと、無限ループになるのはなぜですか? for はNSView-initのですが、指定された初期化子ではないためNSObjectです。そのため、指定されたイニシャライザNSViewを呼び出すようにオーバーライドします-initWithFrame:-initから電話をかけた場合-initWithFrame:は、-initWithFrame:呼び出し-init呼び出し-initWithFrame:呼び出し-init:呼び出し…</p>

これは…ということですか?いいえ、これは必須ではないためです。伝聞ではなく、実際の文書を理解する必要があります。

于 2010-10-23T08:26:05.377 に答える
3

サブクラスの initWithFrame からスーパーの init を呼び出すと、無限ループになるのはなぜですか?

あなたが言うようにC++のバックグラウンドから来て、主な問題はおそらくパラダイムを呼び出すC++メソッドに慣れていることです. Objective-C では、オブジェクトの関数を呼び出しません。メソッドを呼び出すと言うのは、技術的に完全に正しいとは言えません。Objective-C では、オブジェクトにメッセージを送信すると、オブジェクトがメッセージの処理方法を決定します。通常は、クラス内のメソッドを検索して呼び出すだけです。その結果、クラス階層内のどのバージョンのメソッドがメッセージによって呼び出されるかを制御できなくなります。これは常に、メッセージの送信先オブジェクトのクラスに属するメソッドです (1 つのケースを除いて)。C++ には非仮想関数がなく、コンストラクターさえないかのようです。

これに対する 1 つの例外は、super にメッセージを送信する場合です。その場合、クラスのメソッドはバイパスされます。あなたが知っているように、これは無限ループにつながる可能性があります。その理由は、関数を呼び出すのではなく、メッセージを送信するためです。したがって、クラス SubKlass[super methodB]の methodA が Klass の methodB の実装を送信すると、呼び出されます。その後、[self methodA]self がまだ SubKlass のインスタンスである場合、それは魔法のように Klass のインスタンスに変換されていないため、SubKlass の methodA が呼び出されます。

これが、イニシャライザのルールが非常に複雑に見える理由です。指定されたイニシャライザのみが他のイニシャライザのいずれかを送信しないことが保証されているため、指定されたイニシャライザのみをイニシャライザのスーパーに安全に送信できます。

于 2010-10-23T10:05:35.047 に答える
1

C++ の観点から:

サブクラスがある場合、サブクラスの init 内から同じ init 関数を使用してスーパークラスを初期化することになっていると聞いたことがあります。つまり、サブクラスの init は [super init] を呼び出し、サブクラスの initWithFrame は [super initWithFrame] を呼び出す必要があります。

それは真実ではない。それは単に一般的です。有効な初期化子として文書化されている任意のスーパークラス初期化子を自由に呼び出すことができます。

次のように表示すると役立つ場合があります。スーパークラスの初期化子を見て、サポートされているものを判断してください。

  • 指定された初期化子がある場合があります
  • 新しいイニシャライザが存在する場合があります (たとえば、スーパースーパークラスに引数を追加するイニシャライザ)。
  • スーパースーパークラスから継承された初期化子がある場合があります

指定された初期化子の場合: 保護されていると見なします

新しいイニシャライザの場合: 保護されていると見なします

継承された初期化子の場合:通常、スーパークラスが新しい初期化子を宣言する場合は非公開と見なし、それ以外の場合は保護します

サブクラスの initWithFrame からスーパーの init を呼び出すと、無限ループになるのはなぜですか?

これは、呼び出すべきではない初期化子を呼び出すことの影響 (未定義の動作) です。

これが必要な場合、スーパー クラスに initWithPoint がないという理由だけで、initWithPoint などのサブクラス内に新しい init 関数を作成して、スーパーの init または initWithFrame を呼び出すことができないということですか?

サポートされているスーパークラス初期化子の 1 つを介して呼び出す限り、これは問題ありません。

ここでの質問の核心は、別のスーパークラスを呼び出すことが不適切である理由にあると思います。

objc は、初期化子の非表示/可視性をサポートしていません。スーパークラスのインターフェースに入ると、それはそこにあります(そして、コンパイラが助けてくれないところで悪い選択をすることができます)-初期化子の可視性グラフを決定し、それに応じてサブクラスを書くことが期待されます。objc には、c++ で使い慣れた言語機能がありません。

于 2010-10-23T08:51:10.167 に答える
0

どこから聞いたのかわかりませんが、AFAIKは必須ではありません。スーパークラスのinitメソッドを呼び出す場合は、必要に応じてサブクラスを初期化することができます。どのinitメソッドでも機能します。

ただし、スーパークラスにも同じinit関数がある場合は、その関数を呼び出してから、独自のカスタマイズを追加することをお勧めします。必須ではありません。そのinit関数は、追加するのを忘れる可能性のある初期化と設定を提供する可能性があるため、そうすることをお勧めします。

于 2010-10-23T07:20:37.957 に答える