何时在Objective-C中使用responsToSelector


67
- (void)someMethod
{
    if ( [delegate respondsToSelector:@selector(operationShouldProceed)] )
    {
        if ( [delegate operationShouldProceed] )
        {
            // do something appropriate
        }
    }
}

文档说:

仅对于正式协议中的可选方法或非正式协议中的方法,才需要采取预防措施

这是什么意思?如果我使用正式协议,我可以使用[delegate myMethod]

Answers:


85

仅在您认为需要时使用它:检查对象是否实现了您要调用的方法。通常,这是在您具有可选方法或非正式协议时完成的。

我只respondsToSelector在编写必须与委托对象进行通信的代码时使用过。

if ([self.delegate respondsToSelector:@selector(engineDidStartRunning:)]) {
        [self.delegate engineDidStartRunning:self];
    }

有时您可能想respondsToSelector在不确定返回对象的类的任何返回方法和/id或泛型方法上使用NSObject


谢谢。我现在知道了。我注意到您使用self.delegate,这是一个属性。我只使用一个实例变量:id委托。有什么不同?我学习目标-c。再次感谢
Taho 2010年

2
self.delegate与呼叫完全相同[self delegate]。在我的代码中,[self.delegate someMethod]和之间没有区别[_delegate someMethod],但是我倾向于使用点语法,因为它使我清楚地知道哪些变量是我所使用的方法的局部变量,而哪些是实例变量。
kubi

如果您只是开始,那么值得您花时间阅读Apple的Obj-C指南。developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/...
库比什

另一个问题:我是否需要在dealloc和viewDidUnload方法中设置委托= nil(代表类或实现代表的类或两者都不是?)
Taho 2010年

1
不能。几乎应该总是分配而不是保留代表属性。在绝大多数示例中,您没有委托对象,因此您不应保留或释放它。stackoverflow.com/questions/918698/...
库比什

46

只是添加到@kubi所说的话,我又一次使用它是当在较新版本的框架中将方法添加到预先存在的类中时,但是我仍然需要向后兼容。例如:

if ([myObject respondsToSelector:@selector(doAwesomeNewThing)]) {
  [myObject doAwesomeNewThing];
} else {
  [self doOldWorkaroundHackWithObject:myObject];
}

13

正如kubi所述respondsToSelector,通常在拥有符合协议的方法的实例时使用。

// Extend from the NSObject protocol so it is safe to call `respondsToSelector` 
@protocol MyProtocol <NSObject> 

// @required by default
- (void) requiredMethod;

@optional

- (void)optionalMethod;

@end

给定该协议的实例,我们可以安全地调用任何必需的方法。

id <MyProtocol> myObject = ... 
[myObject requiredMethod];

但是,可选方法可能会实现,也可能不会实现,因此您需要在运行时进行检查。

if ([myObject respondsToSelector:@selector(optionalMethod)]) 
{
     [myObject optionalMethod];
}

这样做可以防止选择器无法识别而导致崩溃。


另外,您应该将协议声明为NSObjects扩展的原因,即

@protocol MyProtocol <NSObject> 

是因为NSObject协议声明了respondsToSelector:选择器。否则,XCode会认为调用它是不安全的。


我只是忘了添加<NSObject>解决了我的问题,谢谢
Yogesh Dalavi '17

3

这是个老问题,但是我学会了使用诸如addTarget:@selector(fu :)之类的东西时要非常谨慎,因为方法名称未通过XCODE进行检查也不包含在重构中。这已经给我造成了一些麻烦。因此,现在我变得习惯于始终将诸如addTarget或addObserver之类的内容嵌入到reactsToSelector-Check中,如下所示:

if([self respondsToSelector:@selector(buttonClicked:)]){
    [self.button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}else{
    DebugLog(@"Warning - a class or delegate did not respond to selector in class %@", self);
} 

我知道它并不超级优雅,但我宁愿添加一些样板代码,而不要在App Store中使我的应用程序意外崩溃。


我认为现在可以在xCode中的@selector(methodName :)之类的语句中检查“ methodName:”了吗?
2013年

1
@Grezzo-XCode将仅检查选择器在目标中是否存在。因此,例如,如果您编写@selector(date)而不是@selector(data)XCode不会警告您,因为date选择器存在于NSDateComponents
罗伯特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.