SwiftUI macOS中View结构体能否扩展遵循Git框架RepositoryDelegate代理
实现方案说明
首先回答你的核心疑问:
- 不推荐直接对View类型的struct扩展遵循
RepositoryDelegate代理协议,原因有两个:- 绝大多数第三方框架的delegate属性都是
weak弱引用,仅支持class类型对象,struct是值类型无法被弱引用,就算协议没有限制类类型,赋值后也会出现类型不匹配报错 - SwiftUI的View是值类型,界面重绘时会重新生成实例,delegate回调会指向已经销毁的旧实例,无法正确接收进度更新和处理回调事件
- 绝大多数第三方框架的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
相关产品推荐
相关产品推荐

