21

OK、少し混乱しています。

UIScrollViewのサブクラスがあります。これは、UI要素のように水平方向にスクロールする「テーブルビュー」を試みたものです。UIScrollView自体は、内部で使用するUIGestureRecognizersを設定し、それらのUIGestureRecognizersのデリゲートとして設定されているように見えます。また、水平テーブル要素/セルに独自のUIGestureRecognizerを設定し、独自のUIGestureRecognizerのデリゲートとして独自のクラスを設定しています。私のクラスはUIScrollViewのサブクラスであるため、実行時に、UIGestureRecognizerデリゲート呼び出しは、UIScrollViewの組み込みUIGestureRecognizersと私自身のUIGestureRecognizersの両方のクラスに送信されます。少しPITAですが、気にしないものを渡すことでこれを回避できます。

-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
{ 
   if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]])
      return NO; 
      else
      {  
        if ([super respondsToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)])
           return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
           else 
           return NO;
        }
}

問題は、チェック[super respondsToSelector:@selector()]がYESを返すことですが、実際に呼び出すとreturn [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];、次の例外が発生します。

2012-08-31 12:02:06.156 MyApp [35875:707]-[MyAppHorizo​​ntalImageScrollergestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]:認識されないセレクターがインスタンス0x21dd50に送信されました

私はそれが表示されるべきだと思ったでしょう

-[UIScrollViewgestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]

しかし、それは大丈夫かもしれません。しかし、問題は、それが応答し、その後応答しないと言っていることです。

他の2つのUIGestureRecognizerデリゲートルーチンはこのコードで機能します(明らかに異なるセレクター)。

洞察をありがとう。

4

5 に答える 5

26

クラスのセレクターへの応答をオーバーライドしない限り、現在のインスタンスをチェックするsuperを呼び出すときにデフォルトの実装を使用します。あるタイプのオブジェクトのインスタンスがセレクターに応答するかどうかを確認したい場合は、+(BOOL)instancesRespondToSelector:(SEL)aSelector;

これにより、オブジェクトとその親オブジェクトがチェックされます。したがって、あなたの場合、あなたは次のことをしたいと思います:

[UIScrollView instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]
于 2012-08-31T18:24:04.280 に答える
17

[super respondsToSelector:@selector(frobnosticate:)]あなたが思うことをしません。

respondsToSelector:スーパークラスに移動し、そこで実装を取得してから、現在のオブジェクトで実行します。つまり、superはと同じオブジェクトを表しself、継承ツリーの1つ上のメソッドルックアップを開始するだけです。

respondsToSelector:したがって、「YES」と応答するこのサブクラスで実行していますが、後でgestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:、それを持たないスーパークラスから取得しようとしています。

直接のスーパークラスのインスタンスをチェックするには、jjburkaが推奨するようにを使用しますが、その主題として次のようにinstancesRespondToSelector:提案します。[self superclass]

[[self superclass] instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)];

これにより、クラス名のハードコーディングが回避されます。

于 2012-08-31T18:38:32.160 に答える
5

他の答えを見た後、最良の解決策はを使用すること[[MapControllerSublcass1 superclass] instancesRespondToSelector:_cmd]です。上記で推奨されているようなものを使用すると、クラス階層を変更し、誤って新しいスーパークラスまたはサブクラス[BaseClass instancesRespondToSelector:_cmd]に変更するのを忘れてしまうという問題が発生します。BaseClass

[[self superclass] instancesRespondToSelector:...]上記のコメントで説明されているように正しくなく、実際にはAppleのドキュメントにそのように記載されています(NSObjctのrespondsToSelector:を参照)。1レベルのサブクラス化がある場合にのみ機能するため、実際のソリューションであるかのように見せることができます。私はそれに落ちました。

そして、[[super class] instancesRespondToSelector:...]機能せず、このSO質問の要点です。

たとえば、BaseMapControllerのメソッドのいくつかを実装するが、を実装MKMapViewDelegateしていませんmapView:regionWillChangeAnimated:MapControllerSublcass1から継承しBaseMapControllerます。そしてMapControllerSubclass2から継承しMapControllerSublcass1ます。

私のコードにはこのようなものがあり、正常に動作します。

MapControllerSublcass1.m

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
  if ([[MapControllerSublcass1 superclass] instancesRespondToSelector:_cmd]) {
    [super mapView:mapView regionWillChangeAnimated:animated];
  }
}

MapControllerSubclass2.m

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
  if ([[MapControllerSubclass2 superclass] instancesRespondToSelector:_cmd]) {
    [super mapView:mapView regionWillChangeAnimated:animated];
  }
}
于 2013-07-25T17:34:03.157 に答える
0

電話するとき

[super respondsToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]

これはスーパークラスに行き、その実装を実行しますrespondsToSelector。これにより、インスタンス(この場合はカスタムスクロールビュー)が確認され、そのセレクターに応答するかどうかが判断されます。

電話するとき

[super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];

そのメソッドのスーパークラス実装を使用してメッセージを送信しようとしましたが、この場合は存在しないため、クラッシュが発生します。

jjburkaが最初にそれに到達したように見えます-あなたは電話する必要があります

[UIScrollView instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]

また、認識されないセレクターから使用してもクラッシュしません-[super performSelector:]。performselectorは、セレクターのインスタンス実装を取得します。無限再帰からクラッシュします。

于 2012-08-31T18:36:07.213 に答える
0

同じケースの人の要約として、元の質問には2つの問題があります。

  1. スーパークラスがそのセレクターに応答するかどうかを確認します。これは、@ jjburkaによって提案されているように、を使用して行うのが最適instancesRespondToSelector:です。
  2. プライベートヘッダーで宣言されていても、コンパイラが文句を言わずにスーパークラスのメソッドを実際に呼び出します。これは、カテゴリで再宣言することで適切に実現できます(この質問を参照)。

これをまとめると、次のようになります。

// … In subclass implementation file
@interface UIScrollView () <UIGestureRecognizerDelegate> @end

// … In gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
if ([UIScrollView instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]) {
    return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
}
于 2013-12-05T00:27:54.690 に答える