如何在 SwiftUI 中传递进度值(可能与 combine)?

How to pass the value of progress in SwiftUI(maybe with combine)?

刚开始学SwiftUI,还没来得及Combine。我对此了解不多。 ProgressView中下载进度如何传值。 如何配置ODRManager以及如何在下载过程中传输值,不是0立即1,而是0.0 ... 0.1.0.2 ... 0.8,0.9,1.0 我想知道不同的方式和方法只有 SwiftUI,以及使用 Combine 或其他方法。

非常感谢。

SwiftUI 代码

import SwiftUI

struct ProgressView: View {

    @Binding var value: Float

    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .leading) {
                Rectangle()
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    .opacity(0.3)
                    .foregroundColor(.gray)

                Rectangle()
                    .frame(width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width), height: geometry.size.height)
                    .foregroundColor(.blue)
                    .animation(.linear)
            }.cornerRadius(45.0)
        }
    }
}

struct ContentView: View {

    @State var progressValue: Float = 0.0

    var body: some View {
        VStack {
            Button(action: { //here is the function to download from ondemand }) {
                Text("Download")
                    .padding(.init(top: 10, leading: 30, bottom: 10, trailing: 30))
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(14)

            }
            .padding(.bottom, 30)

            ProgressView(value: $progressValue)
                .environmentObject(self.manager)
                .frame(width: 250, height: 20)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()

    }
}

OnDemand 经理代码

class ODRManager: NSObject {
    var resourceRequest : NSBundleResourceRequest?
    var progress:Float = 0.0 

    func fetchODRResourceWithName(fileName: String) {
        guard self.resourceRequest == nil else {return}
        self.resourceRequest = NSBundleResourceRequest(tags: [fileName])
        progress = Float((resourceRequest?.progress.fractionCompleted)!)
        self.resourceRequest!.progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: nil)
        self.resourceRequest?.conditionallyBeginAccessingResources(completionHandler: { (resourceAvailable) in
            if !resourceAvailable {
                self.resourceRequest!.beginAccessingResources { err in
                    guard err == nil else {
                        print(err as Any)
                        return
                    }
                  print("downloading..")
                }
            } else { 
               print("was downloaded")
            }
        })
    }

    func stopDownloadingFile() {
        guard self.resourceRequest != nil else {
            return
        }
        self.resourceRequest!.endAccessingResources()
        self.resourceRequest!.progress.removeObserver(self, forKeyPath: "fractionCompleted")
        self.resourceRequest!.progress.cancel()
        self.resourceRequest = nil
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "fractionCompleted" {
            DispatchQueue.main.async { [weak self] in
                self.progress = Float((self?.resourceRequest!.progress.fractionCompleted)!)
            }
        }
    }
}
class ODRManager: ObservableObject {
    var resourceRequest : NSBundleResourceRequest?
    @Published var progress:Float = 0.0 

    ... rest of code as before ...
}

现在您可以将它用作 SwiftUI.View

中的任何其他 ObservableObject

目前尚不清楚 ODRManagerContentView 之间的关系,但我建议在它们之间引入一些中间模型(以避免紧耦合),例如

class ProgressItem: ObservableObject {
    @Published var progressValue: Float = .zero
}

所以将 ProgressItem 的相同实例传递给

class ODRManager: NSObject {
    var resourceRequest : NSBundleResourceRequest?
    var progress: ProgressItem? = nil // set up in init
    ...

struct ContentView: View {
    @ObservedObject var progress = ProgressItem() // as variant
    ...
        ProgressView(value: $progress.progressValue)
            .frame(width: 250, height: 20)

你可以加入引擎 & UI 有条件地 w/o 相互依赖。