0

私はObjective Cが初めてで、理解できない奇妙なことがあります。

オブジェクトのNSStringメソッドを呼び出すにはどうすればよいですか? NSDate例えば:

NSString* ptr = [[NSString alloc] init];
[ptr uppercaseString];
NSDate* dPtr = [[NSDate alloc] init];
[dPtr uppercaseString];
id temp;
[temp uppercaseString];

まあ、私は id が何かを指すことができることを理解していますが、uppercaseStringキャストなどを行わずにメソッドの存在をどのように知ることができますか?

私は C++ と Java のバックグラウンドを持っていますが、以前はこのようなことに気付かなかったのです。

説明をいただければ幸いです。

4

4 に答える 4

3

Java や C++ とは異なり、Objective-C の型付けと遅延バインディングは弱いため、キャストを行う必要がないことが説明されています。

これは、オブジェクト指向プログラミングにおける大きな境界線の 1 つです。言語が強力な型付けを使用するため、変数は特定のクラスとそのサブクラスのオブジェクトへの参照 (またはポインター) のみを保持できるか、それとも何かを保持できるかどうかです。変数が任意のオブジェクトを保持できる場合、正確なメソッドの実装は、メッセージの受信時に実行時に解決する必要があります。

Objective-C は Smalltalk ( idを参照) からレイト バインディングの哲学を得ましたが、ますます厳密に型指定された言語 (形式プロトコル、推奨されない型の使用など) に向かっています。ただし、基本は同じままです。

これも理由の 1 つです。C++ とは異なり、Objective-C をマシン上で実行するにはランタイムが必要です。これらのメソッド ルックアップを処理する必要があります。

于 2013-05-25T09:06:39.990 に答える
2

メソッドの存在のチェックは、呼び出しの直前ではなく、メソッドを見つけようとしている間に行われるためです。実際に何が起こるか (かなり簡略化されています)

[obj methodCall];

=> 置き換え =>objc_send(obj, @"methodCall")

C 関数 objc_send の内部 呼び出し自体が解決され、行われます

If(obj.respondsTo(methodCall) Then obj.methodCall();

于 2013-05-25T09:08:46.443 に答える
0

Objective-C のメソッドは、Java または C++ のメソッドと同じではありません。それらはメッセージであり、クラスやオブジェクトから独立して存在します。Photo.hに( CocoaDevCentral から取得) を書き込む場合:

#import <Cocoa/Cocoa.h>

@interface Photo : NSObject {
    NSString* caption;
    NSString* photographer;
}

- caption;
- photographer;

@end

クラスにはキャプションと写真家オブジェクトがあり、メッセージとPhotoに応答すると言っています。これは、これらの 2 つの項目のコードを記述する以前のプロパティの方法でした。captionphotographer

が応答できるPhoto.mように、2 つのメッセージの実装を提供するコードを記述します。Photoしかし、オブジェクトへの送信captionを妨げるものは何もありません。それは、私たちが犬に何を言い、何を聞くかについての古いファー サイドの漫画のようなものです。実行時にエラーが発生します。

では、応答方法がわからないオブジェクトにメッセージを送信するとどうなるでしょうか? 特に何もしていないのであれば、

  1. ランタイム システムは、メッセージをタイプ のものにパッケージ化しますSEL
  2. doesNotRecognizeSelector:そのセレクターを持つオブジェクトにメッセージを送信します。
  3. NSObjectオブジェクトは、 を発生させる実装から継承しますNSInvalidArgumentException

ただし、その前に、メソッドをオーバーライドして介入する機会がいくつかあります。

  • + (BOOL) resolveInstanceMethod:(SEL)aSEL

これにより、実行時に実装をインストールできます。

  • - (id)forwardingTargetForSelector:(SEL)aSelector

これにより、別のオブジェクトを指定してメッセージを受け入れることができます。

  • - (void)forwardInvocation:(NSInvocation *)anInvocation

これにより、メッセージを任意の方法で処理できます。

Objective-C がブロックを獲得する前は、関数型プログラミングに転送を使用するライブラリが多数ありました。すべてがメッセージを理解するNSArrayofがあるとします。次に、すべての口座の残高を別の に集めたいとします。ループする代わりに、ライブラリはメッセージ付きのカテゴリを提供し、次のように記述します。AccountbalanceNSArrayNSArraycollect

NSArray *accounts = ...;
NSArray *balances = [[accounts collect] balance];

の結果にはメッセージ[accounts collect]の実装がありません。balanceどうしてですか? collect図書館から提供されています。代わりに、のすべてのメンバーにメッセージを送信し、それらから新しい を作成するforwardInvocation:実装があります。最近ではブロックを使用することもありますが、それは非常に簡潔で強力な手法でした。balanceaccountsNSArrayenumerateObjectsUsingBlock:

于 2013-05-25T09:33:47.377 に答える