Swift 4:调用其他类函数时出现“Unrecognized selector sent to instance”崩溃
解决Selector调用外部类方法崩溃的问题
这问题我之前踩过坑!核心原因是你没搞清楚Selector调用时的**目标对象(target)**和OC运行时的方法查找规则,咱们一步步拆解解决:
崩溃的核心原因
当你用#Selector指定外部类的方法时,若target还是ViewController实例,运行时会在ViewController里查找这个方法——但方法已经移到外部类了,自然会抛出Unrecognized selector sent to instance错误。另外还有几个容易忽略的细节也会导致这个问题:
具体解决方案
1. 正确设置Target为外部类实例
Selector的target必须是包含该方法的类的实例,而且要确保这个实例不会被ARC提前释放(必须在ViewController里强引用它)。
Swift示例:
class ViewController: UIViewController { // 强引用外部类实例,防止被ARC回收 private let externalHelper = ExternalClass() override func viewDidLoad() { super.viewDidLoad() let testBtn = UIButton(type: .system) // target设为externalHelper,而非self testBtn.addTarget(externalHelper, action: #selector(ExternalClass.btnTapped(_:)), for: .touchUpInside) // 按钮布局... testBtn.frame = CGRect(x: 100, y: 100, width: 200, height: 50) testBtn.setTitle("点击测试", for: .normal) view.addSubview(testBtn) } } class ExternalClass { // 用@objc暴露方法给OC运行时,参数签名必须匹配控件的回调要求 @objc func btnTapped(_ sender: UIButton) { print("外部类方法被触发!") // 如果需要操作ViewController的UI,可通过弱引用持有VC } }
OC示例:
// ViewController.m #import "ViewController.h" #import "ExternalClass.h" @interface ViewController () @property (nonatomic, strong) ExternalClass *externalHelper; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.externalHelper = [[ExternalClass alloc] init]; UIButton *testBtn = [UIButton buttonWithType:UIButtonTypeSystem]; // target设为externalHelper实例 [testBtn addTarget:self.externalHelper action:@selector(btnTapped:) forControlEvents:UIControlEventTouchUpInside]; // 按钮布局... testBtn.frame = CGRectMake(100, 100, 200, 50); [testBtn setTitle:@"点击测试" forState:UIControlStateNormal]; [self.view addSubview:testBtn]; } @end // ExternalClass.h @interface ExternalClass : NSObject // 必须在头文件声明方法,让运行时能找到 - (void)btnTapped:(UIButton *)sender; @end // ExternalClass.m @implementation ExternalClass - (void)btnTapped:(UIButton *)sender { NSLog(@"外部类方法被触发!"); } @end
2. 确保方法能被运行时访问
- Swift中:方法必须加
@objc修饰(如果整个类都需要暴露给OC,可加@objcMembers),且不能是private权限(至少是internal)。 - OC中:方法必须在头文件声明,或者用
@interface ExternalClass ()在.m文件的类扩展里声明(但这样只能在本类和子类访问,跨类调用还是要放头文件)。
3. 严格匹配方法签名
Selector对应的方法参数必须和控件回调的要求完全一致。比如按钮点击的回调必须带(UIButton *)sender参数,如果你写成btnTapped()(无参数),运行时同样会崩溃。
4. 避免循环引用(可选)
如果外部类需要操作ViewController的UI或属性,建议用弱引用持有ViewController,防止循环引用导致内存泄漏:
class ExternalClass { weak var parentVC: UIViewController? init(parentVC: UIViewController) { self.parentVC = parentVC } @objc func btnTapped(_ sender: UIButton) { parentVC?.view.backgroundColor = .orange } } // 在ViewController里初始化: let externalHelper = ExternalClass(parentVC: self)
内容的提问来源于stack exchange,提问作者Chandler Long
相关产品推荐
相关产品推荐

