声明static代理可行但weak代理无效的技术问题排查
Weak代理无法生效的问题排查与解决
我用代理模式在视图控制器间传递消息时遇到问题:声明weak代理无法触发回调,但改用static代理可以正常工作。相关代码如下:
发送消息的视图控制器
protocol SendMessageDelegate: AnyObject { func message(text: String) } final class SendMessageController: UIViewController { weak var delegate: SendMessageDelegate? @objc func button() { sendMessage() } func sendMessage() { let message = "Hello World" // 注:原代码使用了中文引号,需替换为英文引号 delegate?.message(text: message) } }
接收消息的视图控制器
final class ShowMessageController: UIViewController, SendMessageDelegate { let sendMessageController = SendMessageController() override func viewDidLoad() { sendMessageController.delegate = self } func message(text: String) { print("The message is:\(text)") } }
问题原因
核心问题出在ShowMessageController中sendMessageController实例的生命周期:
你在ShowMessageController里用let声明了一个局部实例,但这个实例没有被添加到视图层级,也没有其他强引用持有它。viewDidLoad执行完毕后,这个实例会被立即释放,导致weak修饰的delegate也随之失效,后续调用delegate?.message自然不会触发回调。
而static代理之所以能工作,是因为static变量属于全局强引用,实例不会被释放,但这种写法会带来内存泄漏风险,不建议使用。
解决方法
1. 正确持有并展示SendMessageController实例
如果是通过模态或push方式展示SendMessageController,不要在ShowMessageController里创建局部实例,而是在跳转时初始化并设置代理:
final class ShowMessageController: UIViewController, SendMessageDelegate { override func viewDidLoad() { super.viewDidLoad() } // 示例:点击按钮触发跳转 @objc func presentSendVC() { let sendVC = SendMessageController() sendVC.delegate = self present(sendVC, animated: true) } func message(text: String) { print("The message is:\(text)") } }
此时sendVC会被UIKit的视图层级强引用,不会提前释放,weak代理就能正常接收消息。
2. 验证实例生命周期
可以在SendMessageController中添加deinit方法,检查实例是否被提前释放:
final class SendMessageController: UIViewController { weak var delegate: SendMessageDelegate? deinit { print("SendMessageController 已销毁") } // 其他代码... }
如果在调用sendMessage之前就打印了销毁日志,说明实例被提前释放,需要重新梳理持有逻辑。
3. 修正语法错误
原代码中的字符串使用了中文引号“Hello World”,需替换为英文引号"Hello World",否则会导致编译失败。
内容的提问来源于stack exchange,提问作者Toshiro Vernon
相关产品推荐
相关产品推荐

