仅尝试在我的新项目中实现SwiftUI和Combine。 但陷入其中:
func task() -> AnyPublisher<Int, Error> {
return AnyPublisher { subscriber in
subscriber.receive(Int(arc4random()))
subscriber.receive(completion: .finished)
}
}
这会产生以下编译器错误:
类型'(_)->()'不符合协议'Publisher'
为什么?
更新
实际上Random
只是一个示例。真实的代码将如下所示:
func task() -> AnyPublisher<SomeCodableModel, Error> {
return AnyPublisher { subscriber in
BackendCall.MakeApiCallWithCompletionHandler { response, error in
if let error == error {
subscriber.receive(.failure(error))
} else {
subscriber.receive(.success(response.data.filter))
subscriber.receive(.finished)
}
}
}
}
很遗憾,我没有访问BackendCall API的权限,因为它是私有的。 这是一种伪代码,但是非常接近真实代码。
答案 0 :(得分:1)
您不能使用接受AnyPublisher
的闭包来初始化Subscriber
。您只能从AnyPublisher
中初始化Publisher
。如果要创建自定义Publisher
并在收到订阅者并完成后立即发出单个随机Int
的自定义类型,则可以创建符合Publisher
且自定义类型的自定义类型方法receive(subscriber:)
,完全按照关闭时的操作进行操作。
struct RandomNumberPublisher: Publisher {
typealias Output = Int
typealias Failure = Never
func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
subscriber.receive(Int.random(in: 0...Int.max))
subscriber.receive(completion: .finished)
}
}
然后,在您的task
方法中,只需创建一个RandomNumberPublisher
,然后键入“ ease”即可。
func task() -> AnyPublisher<Int, Never> {
return RandomNumberPublisher().eraseToAnyPublisher()
}
答案 1 :(得分:1)
如果您想要的只是一个随机值,请使用Just
fun task() -> AnyPublisher<Int, Never> {
return Just(Int.random(in: 0...Int.max)).eraseToAnyPublisher()
}
旁注:不要再使用Int(arc4random())
。
答案 2 :(得分:0)
您最好将其包装在Future发布者中,如果希望订阅时响应,也可以用Deferred包装。Future是包装外部异步API调用的绝佳方法,尤其是可以打包的异步API。不能完全控制或容易适应。
Using Combine中有一个"wrapping an async call with a Future to create a one-shot publisher"的示例,它看起来可能与您要尝试的操作非常接近。
如果您希望它返回的值不止一个值,那么您可能希望从PassthoughSubject或CurrentValueSubject中编写一些内容,从而为您提供-> AnyPublisher<YourType, Error>
(或您要查找的内容)的接口。