【发布时间】:2020-02-14 09:01:41
【问题描述】:
我有一个简单的Deferred Publisher,它从磁盘读取数据并将数据显示在SwiftUI List 中,Publisher 在大多数情况下都能正常工作,但有时 它表现不佳,它只是失去了它的价值(这是一个Model 对象的数组)并以finished 消息完成。我尝试了提到here 的解决方法来使用buffer 运算符将值保留在缓冲区中,因为我相信Combine's Publisher 在设计上不会将数据传递到下游,如果订阅者没有请求并因此丢弃此数据并完成,但是使用 buffer 并没有解决问题。
我的代码:
enum FileError: Error {
case someError
}
class ViewModel: ObservableObject {
@Published var modelArray = [Model]()
private var subscriptions = Set<AnyCancellable>()
func readData() {
DataSource()
.readFromBundle(resource: "Sample", type: "json")
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
print("Completion: \(completion)")
}) { array in
self.modelArray = array
}.store(in: &subscriptions)
}
}
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
List(self.viewModel.modelArray) { model in
Text("\(model.name)")
}
}
.onAppear {
self.viewModel.readData()
}
}
}
struct Model: Codable, Identifiable {
var id: Int
var name: String
}
class DataSource {
private let readQueue = DispatchQueue(label: "ReadQueue", qos: .default, attributes: .concurrent)
func readFromBundle (resource: String, type:String) -> AnyPublisher<[Model], FileError> {
Deferred {
Future { promise in
guard let url = Bundle.main.url(forResource: "Sample", withExtension: "json"),
let data = try? Data(contentsOf: url),
let modelArray = try? JSONDecoder().decode([Model].self, from: data)
else {
promise(.failure(.someError))
return
}
promise(.success(modelArray))
}
}
.receive(on: self.readQueue)
.eraseToAnyPublisher()
}
}
This is a link 下载一个工作示例项目。
编辑:
环境:Xcode 11.3.1、iOS 13.3 iPhone 11 Pro Max 模拟器和设备。
gif 截图(注意控制台输出)
EDIT2:
如果我添加任何下游发布者,例如combineLatest,例如在消费者函数readData() 中的sink 之前,则会引入一个新行为,它将异步发布者(readFromBundle)与同步发布者(combineLatest)链接起来) 将导致该值根本无法在iOS 13.3+ 设备上传递,有时会在iOS 13.3 以下的设备上传递,如this link 所述。
【问题讨论】:
-
您的链接项目中是否出现错误?我启动了几次,它成功了......
-
这不是一个错误,它只是因为发布者完成而没有显示数据,是的,它发生在链接的项目中,但并非总是如此(90% 的尝试都是成功的数据)
-
是的,这就是我的意思...但我开始时从未发生过...
-
也许你应该给出“真实”的身份...因为你的身份是双 1...5
-
你在测试什么 ios 版本?我什至现在尝试使用重复计时器,它每次都在 ios 13.2 上工作