首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >下载进度与合并

下载进度与合并
EN

Stack Overflow用户
提问于 2022-03-22 07:38:53
回答 1查看 514关注 0票数 1

我试着用combine和Alamofire来展示文件下载的进展。我有下载机课

代码语言:javascript
复制
class DataManager: NSObject, DataManagerProtocol {
    private(set) var value = 0.0 {
        didSet { subject.send(value) }
    }

    private let subject = PassthroughSubject<Double, Never>()

    func increment(by value: Double) {
        self.value = value
    }
    
    func saveFile(urlString: String, fileName: String) -> AnyPublisher<Double, Never> {
        download(urlString: urlString, fileName: fileName)
        return subject.eraseToAnyPublisher()
    }
    
    private func download(urlString: String, fileName: String) {
        AF.download(urlString)
            .downloadProgress { [self] progress in
                print("Download Progress: \(progress.fractionCompleted)")
                increment(by: progress.fractionCompleted)
            }
            .responseData { response in
                if let data = response.value {
                    print("data recieved")
                    self.writeToFile(data: data, fileName: fileName)
                }
            }
    }
    
    func writeToFile(data: Data, fileName: String) {
        // get path of directory
        
        guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
            return
        }
        // create file url
        let fileurl =  directory.appendingPathComponent(filename)
        if FileManager.default.fileExists(atPath: fileurl.path) {
            if let fileHandle = FileHandle(forWritingAtPath: fileurl.path) {
                print("FileExist")
            } else {
                print("Can't open file to write.")
            }
        } else {
            // if file does not exist write data for the first time
            do {
                try data.write(to: fileurl, options: .atomic)
            } catch {
                print("Unable to write in new file.")
            }
        }
    }
}

在控制台中,我看到并下载了成功文件

下载进度: 0.2707762694368025下载进度: 0.30361701168087313下载进度: 0.45961053734020857下载进度: 0.5088716507063145下载进度: 0.5827633207554733下载进度: 0.615604062999544下载进度: 0.6484448052436146下载进度: 0.7798077742198971下载进度: 0.8783300009521089下载进度:所收到的资料

但是在我的ViewModel中,我没有看到发布进度的变化

代码语言:javascript
复制
import Combine

final class RecordsListViewModel: ObservableObject {
    private var cancellable: AnyCancellable?
    private(set) var progress = PassthroughSubject<Double, Never>()
    private let dataManager: DataManagerProtocol
    
    init(dataManager: DataManagerProtocol) {
        self.dataManager = dataManager
    }
    
    func downloadFile() {
        cancellable = dataManager.saveFile(urlString: "https://i.artfile.ru/2880x1800_1455670_[www.ArtFile.ru].jpg", fileName: "filename.jpg")
            .receive(on: DispatchQueue.main)
            .sink { [weak self] completion in
                print(completion, "completion")
            } receiveValue: { progress in
                print(progress, "progress")
            }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-28 22:35:32

问题是,在saveFile方法中,在ViewModel获取主题之前调用下载方法。我建议将saveFile方法分成两部分。

在DataManager中:

代码语言:javascript
复制
func getSubscription() -> AnyPublisher<Double, Never> {
    return subject.eraseToAnyPublisher()
}
    
func saveFile(urlString: String, fileName: String) {
    download(urlString: urlString, fileName: fileName)
    // or just put the contents of the download method here
}

在ViewModel中,首先获取DataManager的主题,准备并准备下载:

代码语言:javascript
复制
init(dataManager: DataManagerProtocol) {
    self.dataManager = dataManager
    
    cancellable = self.dataManager.getSubscription()
        .receive(on: DispatchQueue.main)
        .sink { completion in
            print(completion, "completion")
        } receiveValue: { progress in
            print(progress, "progress")
        }
}
    
func downloadFile() {
    dataManager.saveFile(urlString: "https://i.artfile.ru/2880x1800_1455670_[www.ArtFile.ru].jpg", fileName: "filename.jpg")
}

我在游乐场上试了一下,用计时器发行商来模拟下载。效果很好。当然,您需要将DataManagerProtocol更改为如下所示:

代码语言:javascript
复制
protocol DataManagerProtocol {
    func saveFile(urlString: String, fileName: String)
    func getSubscription() -> AnyPublisher<Double, Never>
}

编辑:,我刚刚找到了另一种解决问题的方法。只需更改您提供的代码中的一行:

代码语言:javascript
复制
func saveFile(urlString: String, fileName: String) -> AnyPublisher<Double, Never> {
    defer { download(urlString: urlString, fileName: fileName) }
    return subject.eraseToAnyPublisher()
}

在函数完成之前,即使在返回之后,延迟块也将被直接删除。我不确定这是否会使你的代码难以阅读。但为了完整起见,我想我应该提一下这个选项。如果有人有更多的延迟经验,请在评论中告诉我,如果这会更多地被滥用。

顺便说一下,我认为您希望将增量方法的内容更改为:

代码语言:javascript
复制
self.value += value
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71568376

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档