You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用perform调用ViewController中@objc方法触发崩溃求助

问题分析与解决

从崩溃日志里的核心报错信息就能定位问题:

-Business_Name.RPLabel test]: unrecognized selector sent to instance 0x7fd444d03e30

简单说就是:系统尝试给一个RPLabel对象发送test方法,但RPLabel根本没实现这个方法。

为啥会搞成这样?看你写的调用代码:

perform(#selector(MainScreenViewController().test))

这里犯了两个关键错误:

  1. 你用MainScreenViewController()创建了一个全新的、完全没经过VC生命周期初始化的实例——这个对象和你界面上正在显示的MainScreenViewController是八竿子打不着的两个东西。
  2. 你调用的perform(_:)如果不指定target,默认会把消息发给当前调用这个方法的对象。从崩溃栈的调用路径能看到,这个perform是在RPLabel的setup方法里触发的,所以消息被发给了RPLabel实例,而不是你想要的MainScreenViewController,自然就触发了“未识别选择器”的崩溃。

解决方法

方法1:获取正确的MainScreenViewController实例直接调用

你得先拿到界面上正在运行的MainScreenViewController对象,而不是随便new一个。比如如果它是TabBarController的第一个子控制器,可以这么获取:

// 假设当前调用者是某个VC,通过tabBarController获取目标VC
if let tabBarVC = self.tabBarController,
   let mainVC = tabBarVC.viewControllers?.first as? MainScreenViewController {
    // 直接调用方法
    mainVC.test()
    // 要是需要延迟调用等场景,再用perform
    // mainVC.perform(#selector(MainScreenViewController.test))
}

如果是通过导航栈跳转的,可以从导航栈里查找:

if let mainVC = navigationController?.viewControllers.first(where: { $0 is MainScreenViewController }) as? MainScreenViewController {
    mainVC.test()
}

方法2:用更健壮的跨VC通信方式(推荐)

直接硬编码获取VC实例的耦合性太高,推荐用通知中心或者代理模式来实现:

通知中心实现

在MainScreenViewController里注册通知:

override func viewDidLoad() {
    super.viewDidLoad()
    // 注册通知
    NotificationCenter.default.addObserver(self, selector: #selector(test), name: NSNotification.Name(rawValue: "TriggerMainScreenTest"), object: nil)
}

deinit {
    // 记得销毁通知,避免内存泄漏
    NotificationCenter.default.removeObserver(self)
}

然后在需要触发调用的地方发送通知:

NotificationCenter.default.post(name: NSNotification.Name(rawValue: "TriggerMainScreenTest"), object: nil)

代理模式实现

先定义代理协议:

protocol TestTriggerDelegate: AnyObject {
    func triggerTest()
}

在MainScreenViewController里实现代理:

class MainScreenViewController: UIViewController, TestTriggerDelegate {
    func triggerTest() {
        test()
    }
    
    // 其他业务代码...
}

在需要触发调用的对象里添加代理属性:

class YourOtherVC: UIViewController {
    weak var delegate: TestTriggerDelegate?
    
    // 需要调用的地方
    func callTest() {
        delegate?.triggerTest()
    }
}

最后在初始化YourOtherVC的时候设置代理:

let otherVC = YourOtherVC()
otherVC.delegate = self // 这里的self是MainScreenViewController实例
navigationController?.pushViewController(otherVC, animated: true)

方法3:明确指定perform的target

如果你一定要用perform方法,必须明确指定目标对象:

// 先拿到正确的mainVC实例
let mainVC = ... // 获取当前界面的MainScreenViewController实例
mainVC.perform(#selector(MainScreenViewController.test))

内容的提问来源于stack exchange,提问作者Joe Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:08