2011-07-20 7 views
5

は、ビューコントローラの実装からの抜粋です:理解Objective-Cのスコープの問題

- (void)myOtherAwesomeMethod 
{ 
    [self myAwesomeMethod]; // Compile ERROR here: Receiver type for instance message does not declare a method with selector 
} 

- (void)myAwesomeMethod 
{ 
    NSLog(@"%@", @"Calling my awesome method..."); 
} 

- (void)viewDidLoad 
{ 
    [self myAwesomeMethod]; 

    [self myOtherAwesomeMethod]; 
} 

私はmyAwesomeMethod方法が私のヘッダファイルで宣言されていないが、なぜそれは私がviewDidLoadmyAwesomeMethodを呼び出すことができるということです、 myOtherAwesomeMethodにはありませんか?

このエラーの解決方法は、私のヘッダーファイルにメソッドを宣言することですが、なぜこれが起こっているのか理解したいと思います。

+0

ここで、あなたは '-myOtherAwesomeMethod'を呼び出していますか? – vikingosegundo

+1

私はそれがエラーではなく警告であると信じていますか? – tia

+0

また、文字列をNSLogするだけで、フォーマットする必要はありません。 –

答えて

11

Cでは、ルールは:です。使用する前に宣言する必要があります。

ファイルは上から順にコンパイルされます。あなたのコードで何が起きているのですか?

  1. コンパイラは、クラスの@interface宣言を読み込みます。どちらのメソッドもヘッダーファイルで宣言されていないと言うので、どちらもまだシンボルテーブルにありません。

    あなたのシンボルテーブルが含まれています。まだ何も

  2. コンパイラがmyAwesomeMethodためのメソッド定義を読み込みません。まだ宣言していないので、シンボルテーブルに追加されます。このメソッドの本体には、NSLogへの呼び出しが含まれています。これは、Appleによって提供されたヘッダーでずいぶん前に宣言されています。

    あなたのシンボルテーブルが含まれています:myAwesomeMethod

  3. コンパイラはviewDidLoadためのメソッド定義を読み込みます。実際にはスーパークラスのヘッダーファイルで宣言されています。このメソッドの本体には、見つかったmyAwesomeMethodへの呼び出しが含まれています。 myOtherAwesomeMethodへの呼び出しも含まれています。聞いたことがない!

    これはエラーではありません。呼び出しを行うコードが生成される可能性があるためです。引数の型の使用方法(この場合は引数なし)によって引数の型を推論することができます。ただし、戻り値を使用しないという理由だけで、戻り値の型がわからないというわけではありません。したがって、呼び出しがidを返し、警告が生成されるという前提で処理が進められます。

    あなたのシンボルテーブルが含まれています:myAwesomeMethod

  4. を最後に、コンパイラはmyOtherAwesomeMethodためのメソッド定義を読み込みます。シンボルテーブルに追加されます。テーブル内にあるmyAwesomeMethodへの呼び出しを含む本文をコンパイルします。終わりよければ全てよし。ファイルの終わりに

    、あなたのシンボルテーブルが含まれています:myAwesomeMethodを、myOtherAwesomeMethod

あなたはJavaのような言語から来ている場合、これは愚かに見えるかもしれませんが、Javaは違っCよりも働くためですJavaでは、ソースコードをコンパイルしてリンクします。ソースコードまたはクラスファイルのいずれかを使用することなく、別のクラスを参照するクラスをコンパイルすることはできません。それは面倒なことかもしれませんが、一方で、定義以外の宣言については決して必要ありません。

Cでは、コンパイルとリンクは異なるステップです。コンパイラは、他の場所で定義されている可能性のあるシンボルを参照するオブジェクトコードを生成します。宣言を使用して正しいコードが生成されていることを確認します。リンカは、これらすべてのシンボルを静的または動的な他のライブラリの定義と照合する責任があります。

Objective-Cでは、オブジェクトがメッセージに応答できるかどうかをコンパイル時/リンク時に知る方法がないため、リンカーはObjective-Cメッセージについて実際には気にしません。したがって、メソッドを定義しなくてもそれを得ることができれば、例外をスローします。

+0

おかげで@benzado、私は注文が犯人であることが分かった。私はどこにでも宣言する必要はありませんが、メソッド定義は呼び出される前に来る必要があります。私は素晴らしい解説のためにあなたの答えをとにかく受け入れています。 – pixelfreak

0

なぜ私はそれがviewDidLoadで動作するのかわかりません。

エラーは "メソッドを宣言しませんでした"と表示されます。それは、(典型的にはヘッダーの)宣言を探しているというヒントです。つまり、関数プロトタイプです。

しかし、宣言がヘッダーになければならないということは何もありません。ファイルの外側からそのメソッドを呼び出さない場合は、実装ファイルの先頭に置くことができます。