3

Objective-cはかなり新しいですが、かなり一般的な状況に遭遇しました。ClassAに、ClassBだけが知っているオブジェクトでメソッドを実行するようにClassBに依頼してもらいたい(そしてClassAには知られていないメソッドを使用する) )。

私はこれを行う2つの方法を見つけました:performSelector:forwardInvocation: -しかし、私はもっと学び、それぞれの理解を固めたいと思います。私はこのメモをアップルデベロッパのドキュメントで見つけました:

[performSelector:内の] aSelector引数は、引数をとらないメソッドを識別する必要があります。オブジェクト以外のものを返すメソッドの場合は、NSInvocationを使用します。

..つまり、 -(id)methodNameで始まるメソッドはperformSelector:を使用しますが、-(int)nonObjectMethodNameはforwardInvocation:を使用しますか?

また、 (void)を返すメソッドはどうですか?または非IDオブジェクトを返すメソッド(例:(NSString)

4

3 に答える 3

7

No.-forwardInvocation:は、メッセージ転送メカニズムの一部として使用されます。メッセージ転送について心配する必要はありません。実際にはプロキシ オブジェクトによってのみ使用され、使用する必要がなく、使用していることを知っている可能性が高いからです。

-performSelector:メッセージの戻り値の型が互換性があると仮定するidため、戻り値の型が異なるメッセージを送信するために使用される場合 (たとえば、long long32 ビット システムの a などのポインターより幅が広い、または異なるレジスタ/アドレスを介して返される) を使用する場合は安全ではありませんafloatまたは largeなどstruct)。

そのようなメッセージを間接的に送信したい場合は、クラスのインスタンスを作成してから送信できます。戻り値は呼び出しオブジェクトに格納され、呼び出しオブジェクトを介してアクセスできます。は、このシナリオでは使用されません。NSInvocation-invoke-forwardInvocation:

一般的に言えば、 を使用して-performSelector:いることに気付いた場合、おそらくアンチパターンに対処している可能性があります。この場合、ClassA正式には知らないメッセージを送信しようとしています。別の解決策は、これらのプライベート メソッドを公開することです。


と の両方を所有している場合ClassAは、使用するプライベート メソッドを含む のClassB「プライベート」ヘッダーを作成できます。ClassB他の誰か (Apple など) が を所有しClassBている場合、文書化されていない API を扱っていることになり、Apple はそのような API を使用するアプリを拒否するため、別のアプローチを探す必要があるかもしれません。

プライベート ヘッダーを作成するには、Xcode に移動し、新しいヘッダー ファイルを作成します。「ClassB+Internal.h」または「ClassB+PrivateMethodsForMeOnly.h」のような名前を付けます。あなたのプロジェクトにとってプライベートなものとして扱ってくださいClassB。この新しいヘッダーに、次を追加します。

#import "ClassB.h" // so we get the original class definition

@interface ClassB (PrivateMethodsForMeOnly)
- (double)someMethod;
- (const struct low_level_c_type_t)otherMethod:(int)i;
// etc. etc. etc.
@end

そしてClassA.m(これらのメソッドを使用するすべての人に公開したくない 場合を除いて)、include セクションに次の行を追加します。ClassA.hClassA

#import "ClassB+PrivateMethodsForMeOnly.h"

ClassAその後、新しいカテゴリのこれらのメソッドにアクセスできます。

于 2012-07-07T23:44:26.180 に答える
0

わかりました、それはいくつかの質問です。

まず、「forwardInvocation」を忘れてください。これは、プロキシオブジェクトを作成するだけでよいメソッドです。

呼び出しは[NSInvocationinvocationWithMethodSignature...]で作成され、セレクター、引数、およびターゲットオブジェクトで埋められ、最終的にはそれを「呼び出す」だけです。これが、メソッド呼び出しを送信(および保存)する方法です。

Performselectorにはいくつかのバリエーションがあり、そのうちのいくつかはパラメーターを受け取るか、遅延後に呼び出すか、別のスレッドでメソッドを実行します。これはより「直接的な」呼び出しです。NSInvocationは、必要になるまで他のオブジェクトと同じように保持できるオブジェクトですが、「performselector」はほとんどすぐにメソッドを実行します。

戻り値に関しては、私は通常、ドキュメントの内容に固執します。メソッドがidを返す必要があると指示された場合は、オブジェクトを返します(任意のオブジェクトポインタは問題ないので、NSString *は問題ありません。nilを返すことも問題ありません。これは「void」の場合をほぼカバーします)。voidやintではありません。

また、performselectorの呼び出しはそれほど一般的ではないことに注意してください。ほとんどの場合、「[MyObject SomeMethod:SomeParameter];」のように呼び出しをハードコーディングするだけです。PerformSelectorスタイルのメソッドを呼び出すのは特殊な場合です。GUIオブジェクトのターゲット/アクションはそのような場合の1つであり、呼び出されるセレクターがオブジェクトに格納されているため、ハードコーディングすることはできません。

于 2012-07-07T23:57:07.907 に答える
0

の目的は-forwardInvocation:、単にあきらめるのではなく、オブジェクトが他のオブジェクトを認識しないメッセージを送信しようとすることです。NSInvocation には、セレクターだけでなく、メッセージのすべてのパラメーターが含まれます。NSProxyが使用していますが、私の記憶が正しければ、分散オブジェクトの前に使用していました。これは、「このクラスが処理できないすべて」の委譲を実装する 1 つの方法です。

Objective-C ドキュメントのメッセージ転送に関するセクションを読む必要があります。

于 2012-07-08T09:36:17.053 に答える