2010-11-24 4 views
13

iOS 4の前に、マップビューに追加された各MKAnnotationViewにオブザーバを追加して、選択したメソッドをリッスンしていたので、ユーザーがピンをタップしたことを知りました。メソッドのプロトコルをテストするには?

これはiOS 4.2までうまくいきました。私は注釈ビューが実際に再利用されていることに気付きました。そして、それは何らかの形でオブザーバーとうんざりしています。

私はメソッドをMKMapViewDelegateから私のニーズに使用できますが、これはiOS 4.0 SDKにのみ追加されていることがわかります。

互換性を維持するために、このメソッドを代理人に実装し、MKMapViewDelegateプロトコルでこのメソッドが存在するかどうかを条件的にチェックして、存在しない場合は注釈ビューにオブザーバーを追加します。

プロトコルメソッドでこれを行うにはどうすればよいのですか?クラスがnilでないかどうかを確認する方法と同様です。

UPDATE

ダニエルDickisonが指摘したように、私の代理人は、4.0以降のデバイスのための-mapview:didSelectAnnotationView:を実施しているので、私は、respondsToSelector:を使用することはできません。私が必要とするのは、そのデバイス上のプロトコルが-mapview:didSelectAnnotationView:メソッドまたはの場合、MKMapViewがそのメソッドをデリゲートで探すかどうかをチェックすることです。

実行中のiOSバージョンのテストを終了しました。 4.0より大きい場合、MKMapViewはそのメソッドを探して呼び出します。

if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 4.0) 
    [self setupObserver]; 

これは元の問題を解決しますが、方法の実際のプロトコルを何らかの形でチェックすることはまだ興味深いでしょう。

答えて

5

です。だから私はあなたの質問を正しく理解している場合は、実行時にマップビューがmapView:didSelectAnnotationView:メッセージをそのデリゲートに送信するかどうかを調べる必要があります。しかし、conformsToProtocol:またはrespondsToSelector:を使用することはできません。なぜなら、デリゲートを実装しているので、プロトコルを採用し、メソッドを実装しているからです。

私が考えることができるのは、mapRectThatFits:のように、iOS 4のMKMapView(デリゲートではない)に追加された他の方法を確認することだけです。

もう1つの可能性は、Objective-C runtime libraryを使用して、Protocolオブジェクトを照会することです。しかし、これはおそらく過剰です。また、アプリケーションをビルドするときにProtocol object is created by the compilerが動作するとは思えません。また、ランタイムがコンパイルされたものではなく、UIKit SDKで定義されたMKMapViewDelegateプロトコルオブジェクトを取得する可能性があります。

3

私はあなたがNSObject conformsToProtocolをしたいと思います - のようなもの:もしあなたがそれは、あなたがそうでなければ、あなたがやっているように聞こえるいる(具体的な方法をチェックすることができますので、私はrespondsToSelector:メソッドを使用します

BOOL test = [myObject conformsToProtocol:@protocol(MKMapViewDelegate)]; 
2

を特定のプロトコルをチェックするために探して、@エリックの答えは良いものです)。このSO postは、この方法で使用することについて話しています。

基本的に、あなたがそれを使用したい方法はトリッキー一つだ

SEL methodName = @selector(mymethod:); 
BOOL test = [object respondsToSelector:methodName]; 
+1

Chris - SEL変数名として予約キーワードselectを使用したくない場合があります。 – DHamrick

+0

@DHamrick、あなたは絶対に正しい...だから私はすぐに手紙を書きました。 –

+1

"respondsToSelector"はあなたが尋ねる唯一のオブジェクトなので、使用することはできません! MKMapViewがデリゲートからそのメソッドを探しているかどうかを調べる必要があります。 –

0

私は少し違ったアプローチをとってきました。

私は単純に#ifdef (__iPHONE_OS_VERSION_MIN_REQUIRED...を使用し、必要に応じてオブザーバーを追加し、-mapview:didSelectAnnotationView:デリゲートメソッドを使用します。

+0

「#ifdef(__iPHONE_OS_VERSION_MIN_REQUIRED)」は実行時ではなくビルド時に解決されるため、アプリケーションをビルドすると、実行中のデバイス/ OSに関係なく常に同じことが実行されます。 –

+0

はい、 – joshpaul

+0

これは動作しません。実行時には、ビルド時ではなく、デバイスのiOSバージョンを知る必要があります。 '__iPHONE_OS_VERSION_MIN_REQUIRED'は、デバイス/ iOSが何であってもビルド設定で指定した値を常に返します。あなたがそれを実行しているバージョンです – leolobato

26

オブジェクトインスタンスが存在しないため、メッセージセレクタに応答するかどうかを尋ねることができ、プロトコルがサポートされていることを既に知っていますが、ただ1つのメソッドを探しているだけです - protocol_getMethodDescriptionを使用する必要がありますクラスインスタンスとオプション)を返します。

#import <objc/runtime.h> 

struct objc_method_description hasMethod = protocol_getMethodDescription(@protocol(MKMapViewDelegate), @selector(mapView:didSelectAnnotationView:), NO, YES); 

if (hasMethod.name != NULL) 
{ 
... 
} 
+0

プロトコルが '@protocol(MKMapViewDelegate)'として参照されるべきではありませんか?いずれにしても、ランタイムではなくSDKによって提供されるMKMapViewDelegateを使用します。 –

+0

あなたは@protocol(私はコードを修正しました)については正しいですが、チェックはランタイムなので、アプリケーションの実行時に存在していたプロトコルを調べます。おそらく、MKMapKitフレームワークは弱くリンクされている必要があります(アプリケーションターゲットでは「情報を見る」を実行し、次に「一般」タブでフレームワークのリストを見て、MapKitを「必須」から「弱」に変更します)。 –

+0

このドキュメントの「プロトコルオブジェクト」セクションの最後の2つの段落を確認してください - ランタイムではなくSDKによって定義されたプロトコルを取得するかもしれないことを意味すると思います。 http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15-TPXREF149 –

関連する問題