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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:35:10