Swift框架委托协议设计困境:兼顾值类型与避免循环引用
解决Swift委托协议同时支持值类型与类类型的方案
针对既要支持SwiftUI结构体(值类型),又要避免类类型强引用循环的问题,以下是几种可行的无冗余解决方案:
方案一:类型擦除封装器(推荐)
通过创建一个类型擦除的包装类,统一处理值类型的直接引用和类类型的弱引用,使用者无需关注内部细节:
// 基础委托协议,无AnyObject约束,支持所有类型 protocol MyDelegate { func didReceiveNotification() } // 类型擦除的包装器,统一两种引用逻辑 class AnyMyDelegate { private let _invoke: () -> Void // 初始化值类型委托(比如SwiftUI视图) init<T: MyDelegate>(_ delegate: T) { _invoke = { delegate.didReceiveNotification() } } // 初始化类类型委托,自动处理弱引用 init<T: MyDelegate & AnyObject>(weak delegate: T) { _invoke = { [weak delegate] in delegate?.didReceiveNotification() } } // 对外暴露的委托方法 func didReceiveNotification() { _invoke() } } // 框架中的组件示例 class FrameworkManager { var delegate: AnyMyDelegate? func triggerEvent() { delegate?.didReceiveNotification() } }
使用示例
- SwiftUI结构体(值类型):
struct MyView: View, MyDelegate { let manager = FrameworkManager() init() { manager.delegate = AnyMyDelegate(self) } func didReceiveNotification() { // 处理通知逻辑 } var body: some View { /* 视图内容 */ } }
- UIKit类(引用类型):
class MyVC: UIViewController, MyDelegate { let manager = FrameworkManager() override func viewDidLoad() { super.viewDidLoad() manager.delegate = AnyMyDelegate(weak: self) } func didReceiveNotification() { // 处理通知逻辑 } }
方案二:协议拆分+共享默认实现
拆分出基础值类型协议和类专属协议,通过扩展共享逻辑,避免代码冗余:
// 基础协议,支持值类型 protocol MyBaseDelegate { func handleUpdate() } // 类专属协议,继承基础协议并添加AnyObject约束 protocol MyClassDelegate: MyBaseDelegate, AnyObject {} // 扩展基础协议,提供默认实现(所有实现者共享) extension MyBaseDelegate { func handleUpdate() { // 默认处理逻辑 } } // 框架组件,同时支持两种委托 class FrameworkHandler { // 类类型委托:weak修饰避免循环引用 weak var classDelegate: MyClassDelegate? // 值类型委托:普通引用 var valueDelegate: MyBaseDelegate? func triggerUpdate() { classDelegate?.handleUpdate() valueDelegate?.handleUpdate() } }
使用示例
- SwiftUI结构体实现
MyBaseDelegate,赋值给valueDelegate - UIKit类实现
MyClassDelegate,赋值给classDelegate
这种方式逻辑清晰,协议代码只维护一次,使用者根据自身类型选择对应的委托属性即可。
方案三:泛型委托属性+条件约束
通过泛型和where子句,在框架组件中区分类类型和值类型的委托声明:
protocol MyDelegate { func performAction() } class FrameworkComponent<T: MyDelegate> { // 仅当T是类类型时可用的weak委托 weak var weakDelegate: T? where T: AnyObject // 值类型委托 var valueDelegate: T? func invokeDelegate() { (weakDelegate ?? valueDelegate)?.performAction() } }
使用者在实例化组件时指定泛型类型,根据自身类型选择对应的委托属性赋值。
内容的提问来源于stack exchange,提问作者user3740240
相关产品推荐
相关产品推荐

