super respondsToSelector:返回true但实际上调用super(selector)给出"无法识别的选择器发送到实例"

cha*_*bag 19 delegates objective-c super uigesturerecognizer respondstoselector

好的,我有点困惑.

我有一个UIScrollView的子类,这是我尝试像UI元素一样水平滚动"表视图".UIScrollView本身设置它在内部使用的UIGestureRecognizers,它似乎将自己设置为那些UIGestureRecognizers的委托.我在我的水平表元素/单元格上也有自己的UIGestureRecognizer设置,我自己的类设置为我自己的UIGestureRecognizer的委托.由于我的类是UIScrollView的子类,在运行时,UIGcureRecognizer委托调用来到我的类,用于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;
        }
}
Run Code Online (Sandbox Code Playgroud)

问题是检查[super respondsToSelector:@selector()]返回YES,但是当我实际调用它时,return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];我得到以下异常

2012-08-31 12:02:06.156 MyApp [35875:707] - [MyAppHorizo​​ntalImageScroller gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]:无法识别的选择器发送到实例0x21dd50

我本以为应该表明

- [UIScrollView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]

但那可能没问题.但问题是,它说它响应然后不响应.

另外两个UIGestureRecognizer委托例程使用此代码(显然是不同的选择器).

感谢您的任何见解.

jjb*_*rka 24

除非你覆盖对类中选择器的响应,否则在调用super时将使用默认实现,这将检查当前实例.如果要查看某种对象的实例是否响应选择器使用+(BOOL)instancesRespondToSelector:(SEL)aSelector;

这将检查对象及其父对象.所以在你的情况下你想要以下内容:

[UIScrollView instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]
Run Code Online (Sandbox Code Playgroud)


Jos*_*ell 17

[super respondsToSelector:@selector(frobnosticate:)] 不做你的想法.

它转到超类,获取那里的实现respondsToSelector:,然后在当前对象上运行它.换句话说,super表示相同的对象self,它只是在继承树中启动方法查找一步.

所以你respondsToSelector:在这个子类上运行,它回复"是",但后来试图gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:从超类中获取,而超类没有它.

要检查直接超类的实例,你会instancesRespondToSelector:像jjburka推荐的那样使用,但我建议[self superclass]作为主题,如下:

[[self superclass] instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)];
Run Code Online (Sandbox Code Playgroud)

这避免了硬编码类名.

  • 如果再次将其子类化.子类调用它的超类,它仍然是原始类的子类.如果我有MyScrollView这是UIScrollView的子类,然后我有MyOtherScrollView这是MyScrollView的子类,当你在MyOtherScrollView中时,`[[self superclass] instancesRespondToSelector:@selector(aSelector)]`与`不一样` [UIScrollView instancesRespondToSelector:@selector(aSelector)]` (5认同)
  • Apple推荐反对[[self superclass] instancesRespondToSelector,如http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject的/ respondsToSelector: (4认同)

Rob*_*rto 5

在查看其他答案后,最好的解决方案是使用[[MapControllerSublcass1 superclass] instancesRespondToSelector:_cmd].如果您使用上面推荐的内容,例如[BaseClass instancesRespondToSelector:_cmd],您遇到了更改类层次结构的问题,并且意外忘记更改BaseClass为新的超类或子类.

[[self superclass] instancesRespondToSelector:...]如上面评论中所解释的那样是不正确的,它实际上是在Apple的文档中说明的(参见respondsToSelector:在NSObjct中).只有当你拥有1级子类的作品,所以它给你的错觉,这是一个实际的解决方案.我为它而堕落.

并且[[super class] instancesRespondToSelector:...]不起作用,这是这个问题的重点.

例如,我有一个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];
  }
}
Run Code Online (Sandbox Code Playgroud)

MapControllerSubclass2.m:

- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
  if ([[MapControllerSubclass2 superclass] instancesRespondToSelector:_cmd]) {
    [super mapView:mapView regionWillChangeAnimated:animated];
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 不,你不应该.见上文第二段. (2认同)