You need to enable JavaScript to run this app. SwiftUI macOS中View结构体能否扩展遵循Git框架RepositoryDelegate代理
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI macOS中View结构体能否扩展遵循Git框架RepositoryDelegate代理

实现方案说明

首先回答你的核心疑问:

  • 不推荐直接对View类型的struct扩展遵循RepositoryDelegate代理协议,原因有两个:
    • 绝大多数第三方框架的delegate属性都是weak弱引用,仅支持class类型对象,struct是值类型无法被弱引用,就算协议没有限制类类型,赋值后也会出现类型不匹配报错
    • SwiftUI的View是值类型,界面重绘时会重新生成实例,delegate回调会指向已经销毁的旧实例,无法正确接收进度更新和处理回调事件

推荐实现方式:单独创建ObservableObject类作为代理

这种方式符合SwiftUI数据流规范,也能稳定接收代理回调,同时可以把进度等状态同步到界面上,完整实现代码如下:

import SwiftUI
import Git

// 自定义代理类,同时遵循ObservableObject方便在SwiftUI中使用
class CloneProgressTracker: ObservableObject, RepositoryDelegate {
    // 可以用@Published对外暴露克隆进度,供界面显示
    @Published var cloneProgress: String = ""
    @Published var cloneError: Error?
    
    func repository(_ repository: Repository, didProgressClone progress: String) {
        // 进度回调在主线程更新UI
        DispatchQueue.main.async {
            self.cloneProgress = progress
        }
    }
}

struct File: View {
    @State var pathUrl = "https://github.com/way-to-code/git-macOS.git"
    @State var nameDir = "/Users/"
    // 用@StateObject持有代理实例,生命周期和当前界面绑定
    @StateObject private var progressTracker = CloneProgressTracker()
    
    func cloneReport() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            let url: URL = URL(string: pathUrl)!
            let report = GitRepository(from: url)
            // 绑定代理
            report.delegate = progressTracker
            do {
                try report.clone(at: nameDir)
            } catch let e {
                DispatchQueue.main.async {
                    progressTracker.cloneError = e
                }
                print("Errors \(e).")
            }
        }
    }
    
    var body: some View {
        VStack(spacing: 12) {
            // 可以直接显示当前进度
            Text("克隆进度:\(progressTracker.cloneProgress)")
            if let error = progressTracker.cloneError {
                Text("克隆失败:\(error.localizedDescription)")
                    .foregroundColor(.red)
            }
            Button(action: {
                cloneReport()
            }) {
                Text("Clone").frame(width: 330)
            }
        }
    }
}

struct File_Previews: PreviewProvider {
    static var previews: some View {
        File()
    }
}

注意:如果你的Git框架的代理回调是在子线程执行,所有和UI相关的状态更新一定要切回主线程执行,避免界面异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 20:09:03