如何捕获未识别的选择器发送给实例的异常?

5
我遇到了一些时间后未被识别的选择器发送到实例异常。当我遇到这种情况时,我希望能够跳过它并让我的应用程序继续工作。
然而,我不知道如何捕获它。因为这个代码无法捕获异常:
@property(nonatomic,retain) UIButton *button;
    @try{

       if(button.currentBackgroundImage == nil){//rises exception 
    }
    }@catch(NSException *e){
}

我该如何处理这个问题?谢谢。
3个回答

6
我使用并经常看到的技术是:不要捕获异常,而是检查对象是否响应选择器。
if(![button respondsToSelector:@selector(currentBackgroundImage)] || button.currentBackgroundImage == nil) {
  // do your thing here...
}

3
是的,这是正确的。尽可能避免异常情况是你想要做到的^^。 - borrrden
一段时间后仍然出现以下问题: -[__NSCFType setBackgroundImage:forState:]:向实例发送无法识别的选择器。也许我需要使用按钮属性做些什么。通过这个属性,我保存了按钮实例,当其他按钮被按下时,我将删除之前按下的按钮背景。 - Streetboy
我打开了NSZombie并发现了这个问题:-[UIButton setBackgroundImage:forState:]:消息发送到已释放的实例。当我将背景设置为nil时,是否有可能我的按钮被释放了? - Streetboy
2
不,可能不是,但你的按钮在某个地方超出了范围并被释放了。那是一个不同的问题。 - borrrden
如果您正在使用属性赋值(即 thing.currentBackgroundImage = img),则需要检查的 @selector 是 @selector(setCurrentBackgroundImage)。 - Chris Trahey

2
如果您遇到这个异常,这意味着您的代码存在设计缺陷或错误。忽略异常来修补它并不是正确的做法。尝试找出为什么会向错误的对象发送错误的消息。这将使您的代码更加健壮和可维护。
此外,有时候当对象原本是正确类型但正在被释放时,也会发生这种异常。请注意!
如果您仍想绕过异常,请阅读苹果文档,其中解释了多步骤过程,在运行时将消息绑定到方法实现的方式。有至少两个位置可以通过覆盖NSObject的默认行为来捕获它。

2

我理解回答中告诉你要防止未识别的选择器,因为那是首选方法。

但是,在没有该选项的情况下(例如在我的情况下,Cocoa内部进一步混乱了调用堆栈),您确实可以像您尝试的那样捕获未识别的选择器。

概念证明代码:

Original Answer翻译成"最初的回答"

// Do a really bad cast from NSObject to NSButton
// to get something to demonstrate on
NSButton *object = (NSButton*)[[NSObject alloc] init];

@try{
    // Log the description as the method exists 
    // on both NSObject and NSButton
    NSLog(@"%@", [object description]);

    // Send an unrecognized selector to NSObject
    [object bounds];
} @catch(NSException *e){
    NSLog(@"Catch");
} @finally {
    NSLog(@"Finally");
}

// Print the description to prove continued execution
NSLog(@"Description again: %@", [object description]);

输出:

2019-02-26 14:11:04.246050+0100 app[46152:172456] <NSObject: 0x60000000a6f0>
2019-02-26 14:11:04.246130+0100 app[46152:172456] -[NSObject bounds]: unrecognized selector sent to instance 0x60000000a6f0
2019-02-26 14:11:04.246226+0100 app[46152:172456] Catch
2019-02-26 14:11:04.246242+0100 app[46152:172456] Finally
2019-02-26 14:11:04.246258+0100 app[46152:172456] Description again: <NSObject: 0x60000000a6f0>

正如您所看到的,异常仍被记录在控制台中,但代码继续执行。

最初的回答

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接