動的バインディングが嘘のようだ
-
18-09-2019 - |
質問
Objective-C は動的バインディングを使用します。つまり、メソッド呼び出しは実行時に解決されます。
大丈夫。
そして ドット表記の使用は実際にはメソッド呼び出しに帰着します。
しかし、では、なぜ次のようなことができないのでしょうか。
#import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Intercept the exception @try { @throw [ NSException exceptionWithName:@"Exception named ME!" reason:@"Because i wanted to" userInfo:nil ] ; } @catch( id exc ) // pointer to an exception object? { //NSLog( @"%@ : %@\n", exc.name, exc.reason ) ; // 違法:メンバーのリクエスト//構造や組合ではなく何かの「名前」。. // If objective-c uses dynamic binding, and dot notation // boils down to calling the getter, then // WHY do I have to cast to the concrete type here? // Only works if I cast to the concrete type NSException* NSException* nexc = (NSException*)exc ; NSLog( @"%@ : %@\n", nexc.name, nexc.reason ) ; } [pool drain]; return 0; }
「動的バインディング」と聞くと、「スクリプト言語のように動作するはずだ」と考えてしまいます。 そして、JavaScript のようなスクリプト言語と比較して、Objective-C がいかに柔軟性に欠けているかに驚きました。
解決
あなたは、ランタイムおよびコンパイラを混乱されています。ランタイムはそれに対処する問題はありません。問題は、(構文糖である)ドット表記はObjective-CのオブジェクトとCの構造体との間に明確にするコンパイラのための情報を入力する必要があることである。
あなたは、ドット表記を使用しない場合は、それは動作します:
NSLog( @"%@ : %@\n", [exc name], [exc reason]) ;
タイプがIDでない場合、コンパイラは、それが型を知っている知っているとディスパッチが動作する保証することはできませんが、それはコンパイルして実行されますので、上記の警告を生成します。
基本的に手で問題がコンパイラはドット表記で、オブジェクトとスカラーとの間の差を決定するために十分な情報を持っている必要があり、換言すれば、構造負荷、または客観Cディスパッチを生成するかどうかを知る必要があります種類ます。
他のヒント
のダイナミックバインディングのはの動的型付けのと同義ではありません。 Cは、強く型付けされた言語であり、具体的には、引数または戻り値の型は重要であり、有意にコード生成に影響を与える可能性があります。
のプロパティを具体的にあいまいさを排除するために設計されています。その一環として、この決定は、のないのドット構文はid
に対して使用することを許可します。
具体的には、この状況に対処します:
@interface Foo
- (short) length;
@end
@interface Bar
- (unsigned long long) length;
@end
二つの別々のヘッダファイルで上記を考えると、[anObject length]
のコンパイルは警告を与えます。の両方のヘッダファイルがインポートされているだけのの。唯一の1つのヘッダファイルがインポートされている場合は、呼び出しサイトは、ヘッダに見られる型を返すコンパイルされます。呼び出しサイトは、の他の方法、非常に予想外の結果が返されます。
ドット構文上の制限は、この潜在的なあいまいさを排除します。これはまた、あなたがの理由で、一般的な方法の共同バリアントの宣言を見ていないのです。 C ABIはちょうどきれいにそれをサポートしていない(ということで、Objective-Cのオブジェクト型の共分散をサポートする貧しい仕事をしていません)。
実際には、Objective-Cの開発者は、めったにid
タイプを使用していません。特定の型宣言は、大幅にコードの検証を改善するためのコンパイラを可能にする。
のObjective-Cは動的バインディングをサポートします。ただし、タイプ「ID」のオブジェクトのプロパティを使用することはできません - しかし、あなたはそれをあなたが望む任意のメッセージを送ることができます。 (これはおそらく、現在の定義/実装におけるミスです...しかし今のところわき残しておきましょう。)
あなたがやった場合は、
NSLog(@"%@ : %@", [exc name], [exc reason] );
それが動作します。彼らはとにかく、すべて別々の行にしているとして、あなたは、のNSLog文で改行を置く必要はないことに注意してください。