两处给Swift单例GameCenterFacade设置delegate仅一处生效,如何实现多对象接收回调?
问题解答
单例与代理的关系说明
- 标准代理(Delegate)模式的默认设计就是单接收对象,和是否为单例没有关联。你遇到的覆盖问题是因为常规的delegate属性只声明为单个弱引用对象,后赋值的实例会直接覆盖之前的赋值,所以才会只有最后设置的自定义类能收到回调。
多对象同时接收回调的可行方案
方案1:改造单例实现多播代理(最规范)
修改GameCenterFacade的内部逻辑,将单个delegate替换为弱引用的代理集合,避免循环持有问题,建议使用NSPointerArray实现:
// GameCenterFacade 内部代码 private var delegates = NSPointerArray.weakObjects() // 新增添加代理的公开方法 func addDelegate(_ delegate: GameCenterDelegate) { delegates.addObject(delegate) } // 触发回调时遍历所有代理执行 private func triggerCallback() { delegates.allObjects.forEach { object in guard let delegate = object as? GameCenterDelegate else { return } // 调用对应的协议方法即可 delegate.gameCenterDidReceiveData?() } }
改造完成后,两边都不再执行GameCenterFacade.shared.delegate = self的赋值,统一调用GameCenterFacade.shared.addDelegate(self)即可同时收到回调。
方案2:用通知中心中转回调(改造成本最低)
如果不想改动GameCenterFacade的原有实现,可以用通知做中转:
- 保留其中一个对象作为唯一delegate(比如自定义类),该对象收到回调时发送全局通知
- ViewController监听对应通知执行自身逻辑即可
// 自定义类收到代理回调时 func gameCenterDidReceiveData() { // 自身逻辑处理完成后发通知 NotificationCenter.default.post(name: NSNotification.Name("GameCenterDidReceiveData"), object: nil) } // ViewController viewDidLoad 中添加监听 NotificationCenter.default.addObserver(self, selector: #selector(handleGameCenterData), name: NSNotification.Name("GameCenterDidReceiveData"), object: nil)
方案3:中间代理转发
你可以创建一个独立的中间代理类,作为GameCenterFacade唯一的delegate,内部持有ViewController和自定义类的弱引用,收到回调后分别转发给两个对象即可。
内容的提问来源于stack exchange,提问作者Charlie S
相关产品推荐
相关产品推荐

