结合分配(给:在:)另一个发布者

Combine assign(to: on:) another publisher

这里有一个简单的“下载”class来说明我想做什么。

class Download {
    
    public var progress: CurrentValueSubject<Double, Never> = CurrentValueSubject<Double, Never>(0)
    
    var subscriptions: Set<AnyCancellable> = []
    
    func start(task: URLSessionTask) {
        task.resume()
        task.progress.publisher(for: \.fractionCompleted).sink { [weak self] (newProgress) in
            self?.progress.send(newProgress)
        }.store(in: &subscriptions)
    }
    
}

我希望能够将进度 属性 观察者发布者“重新发布”到我当前的价值主题。如您所见,我目前使用 .sink 函数进行订阅,然后直接调用 CurrentValueSubject 发布者。

我希望能够像这样使用 .assign(to:, on:) 运算符。

task.progress.publisher(for: \.fractionCompleted).assign(to: \.progress, on: self)

但是,这将不起作用,似乎保留用于在 SwiftUI @Published 属性 上“重新发布”的 .assign(to:) 运算符也不起作用。为什么 Combine 在这里没有名副其实?

您需要分配给主题的值,而不是主题本身。值得注意的是 assign(to: ..., on: self) 会导致内存泄漏 ‍♀️.

func start(task: URLSessionTask) {
    task.resume()
    task.progress
        .publisher(for: \.fractionCompleted)
        .assign(to: \.progress.value, on: self)
        .store(in: &subscriptions)
}

因为CurrentValueSubject是一个class,你可以用它作为assign(to:on:)object参数。这样,就没有内存泄漏:

class Download {
    
    public let progress: CurrentValueSubject<Double, Never> = .init(0)
    
    var subscriptions: [AnyCancellable] = []
    
    func start(task: URLSessionTask) {
        task.resume()
        task.progress
            .publisher(for: \.fractionCompleted)
            .assign(to: \.value, on: progress)
            .store(in: &subscriptions)
    }
    
}