点击导航栏按钮触发MyCoordinator menuTapped: unrecognized selector随机崩溃求助
崩溃原因
- 根本原因:
UIBarButtonItem的target属性为unsafe_unretained修饰,并非ARC下的weak类型,当你初始化按钮时传入的target对象被释放后,该target不会自动置为nil,会变成野指针。点击按钮触发事件时,系统会向这个野指针指向的内存地址发送action消息,如果此时这块内存恰好被MyCoordinator实例占用,就会抛出找不到对应选择子的异常,这也是崩溃随机发生的原因——只有野指针地址被其他对象占用时才会触发崩溃。 - 次要隐患:调用delegate方法前未做响应性检查,如果delegate未实现协议方法也会触发同类崩溃;另外协议定义的方法参数为
MyTreeCoordinator类型,调用时传入的是MyCoordinator实例,类型不匹配也可能导致消息转发失败。
修复方案
- 解决野指针核心问题,二选一即可:
- 方案一:保证按钮target的生命周期和按钮本身绑定,将target直接设置为MyCoordinator,确保按钮存在时MyCoordinator不会被释放
- 方案二:使用block封装的UIBarButtonItem,彻底避免target野指针问题,示例代码:
UIBarButtonItem *menuButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"MyImageName"] style:UIBarButtonItemStylePlain handler:^(UIBarButtonItem * _Nonnull sender) { [self.myCoordinator menuTapped]; }]; - 调用delegate前增加响应判断,避免未实现协议方法的崩溃:
- (void)menuTapped { if ([self.delegate respondsToSelector:@selector(menuButtonTapped:)]) { [self.delegate menuButtonTapped:self]; } } - 修正协议参数类型不匹配问题:
@protocol MyCoordinatorDelegate <NSObject> - (void)menuButtonTapped:(MyCoordinator *)myCoordinator; @end - 可选优化:给协议方法添加
@required修饰,编译阶段就能检查未实现协议的问题,提前规避运行时风险。
内容的提问来源于stack exchange,提问作者iOSDude
相关产品推荐
相关产品推荐

