4

iOS13 的发布者组合流在操作员使用调度程序后似乎没有流动。

这是我的代码:

import Foundation
import Combine

struct MyPublisher: Publisher {
    typealias Output = Int
    typealias Failure = Error

    func receive<S>(subscriber: S) where S : Subscriber,
        Failure == S.Failure,
        Output == S.Input {
            subscriber.receive(1)
            print("called 1")
            subscriber.receive(2)
            print("called 2")
            subscriber.receive(completion: .finished)
            print("called finish")
    }
}

MyPublisher()
//    .receive(on: RunLoop.main) // If this line removed, it will be fine.
//    .throttle(for: .milliseconds(1000), scheduler: RunLoop.main, latest: false)) // If this line removed, it will be fine.
//    .debounce(for: .milliseconds(1000), scheduler: RunLoop.main)) // If this line removed, it will be fine.
//    .delay(for: .milliseconds(1000), scheduler: DispatchQueue.main)) // If this line removed, it will be fine.
    .print()
    .sink(receiveCompletion: { completion in
        switch completion {
        case .finished:
            print("finished")
        case .failure(let error):
            print("error:\(error)")
        }
    }, receiveValue: { num in
        print("\(num)")
    })

我希望输出是

1
2
finished

但实际输出什么都不是。

如果我不使用receiveorthrottledebounceor delay。输出会很好。

是错误还是我的代码有问题?

我尝试使用 Playground(Xcode 11 beta3)。

4

2 回答 2

3

订阅:

我不确定为什么它在单线程的情况下有效,但你应该确保调用received(subscription:). subscriber如果您不需要处理订阅者的需求,您可以使用Subscribers.empty

struct MyPublisher: Publisher {

    typealias Output = Int
    typealias Failure = Never

    func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
        subscriber.receive(subscription: Subscriptions.empty)
        _ = subscriber.receive(1)
        Swift.print("called 1")
        _ = subscriber.receive(2)
        Swift.print("called 2")
        _ = subscriber.receive(completion: .finished)
        Swift.print("called finish")
    }
}

任何可取消:

您应该注意到一个警告:

调用 'sink(receiveCompletion:receiveValue:)' 的结果未使用

这应该会出现,因为sink返回一个AnyCancellable

func sink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable

任何返回 an 的东西都会在释放AnyCancellable后立即取消。AnyCancellable

我的猜测是,如果你把它放在另一个线程上,那么当调用方法结束时,cancellable 将在收到订阅之前释放。但是,当在当前线程上接收到它时,它似乎正好及时执行以显示订阅和输出。当前线程退出时,最有可能取消分配可取消对象。

于 2019-07-18T02:16:21.580 回答
2

使用可取消

例如 :

class ImageLoader: ObservableObject {
    @Published var image: UIImage?
    private var cancellable: AnyCancellable?

func fetchImages() {
        guard let urlString  = urlString,
            let url =  URL(string: urlString) else { return }
        cancellable = URLSession.shared.dataTaskPublisher(for: url)
            .map { UIImage(data: $0.data) }
            .replaceError(with: nil)
            .receive(on: DispatchQueue.main)
            .sink { [weak self] in self?.image = $0 }
    }
}
于 2021-01-07T22:31:45.303 回答