I am learning Combine on iOS. This is my code:
struct ContentView: View {
let aiRepsonse = "View the latest news and breaking news today for U.S., world, weather, entertainment, politics and health at abc.com."
@State private var cancellableSet = Set<AnyCancellable>()
@State private var content = ""
func test() {
content = ""
aiRepsonse.publisher
.flatMap{
return Just($0).delay(for: 0.01, scheduler: RunLoop.main)}
.sink { _ in
if content.count != aiRepsonse.count{
print("error! lost data! content.count is \(content.count), aiRepsonse.count is \( aiRepsonse.count)")
print("content is : \(content)")
print("aiRepsonse is : \(aiRepsonse)")
}
} receiveValue: { value in
content += String(value)
}
.store(in: &cancellableSet)
}
var body: some View {
VStack {
Text(content)
.frame(height: 200)
Button(action: {
test()
}, label: {
Text("Test")
})
}
}
}
If you press Test button several times in a short time, the error log will appear.
For example,
error! lost data! content.count is 104, aiRepsonse.count is 117
content is : View the latest news and breaking news today for U., wol, weather eertainmet, politicsnd heathat ac.com.
aiRepsonse is : View the latest news and breaking news today for U.S., world, weather, entertainment, politics and health at abc.com.
I don’t understand why some [Just($0).delay()] publishers do not emit character correctly. Is this a back-pressure problem? Thanks a lot.
>Solution :
Some data is lost because you are using a RunLoop as the schedular. From this post,
RunLoop.mainruns callbacks only when the main run loop is running in the.defaultmode, which is not the mode used when tracking touch and mouse events. If you useRunLoop.mainas a Scheduler, your events will not be delivered while the user is in the middle of a touch or drag.
If you use DispatchQueue.main, no data will be lost.
Another problem is that test might be called when the publisher created by the previous call to test has not completed. This is not much of a problem when the delay is 0.01, but will become a problem when the delay is larger. You will end up having two sinks appending to content at the same time, and content would be longer than expected. This can be solved by cancelling everything in cancellableSet first, before starting a new publisher.