I don't quite understand the pattern of waiting to retrieve data from any async call (any: network, timer, any call that executes asynchronously and I have to wait to perform another one) and use it in synchronously in a different place (how to chain to operations. I saw examples using flatmap by they referred to 2 web calls. In this case I have to retrieve data from the web (a session Id), and save it to further use (it lasts an hour). I read about Operations, DispatchGroups, and don't quite get them to work in here. I have a simple class that gets data from a web service, I have to wait till its downloaded, and save it.
import Foundation
import Combine
import CoreData
struct SessionId:Codable {
let key:String?
let dateTime:Date?
}
class ColppyModel {
var session:SessionId?
var key:String?
var cancellable:AnyCancellable?
init() {
print("saving")
let sess = SessionId(key: "1", dateTime: DateComponents(calendar:Calendar(identifier: .gregorian), year:2020, month:1, day:1).date)
guard let data = try? JSONEncoder().encode(sess) else {return}
let defaults = UserDefaults.standard
defaults.set(data, forKey: "sessionIdKey")
print("Saved \(sess)")
}
func getSessionKey(){
let requestData = ColppyAPIRequests.createSessionIdRequestData()
cancellable = ColppyAPI.sessionKeyRequest(sessionKeyJsonData: requestData)
.replaceError(with: nil)
.map{$0?.response?.data?.claveSesion}
.receive(on: DispatchQueue.global(qos: .userInteractive))
.sink(receiveValue: { (clave) in
let data = try! JSONEncoder().encode(SessionId(key: clave!, dateTime: Date()))
UserDefaults.standard.set(data, forKey: "sessionIdKey")
})
}
func getSessionIDFromUserDefaults() -> SessionId? {
let defaults = UserDefaults.standard
let data = defaults.data(forKey: "sessionIdKey")
guard let safeData = data else { return nil }
guard let sessionId = try? JSONDecoder().decode(SessionId.self, from: safeData) else {return nil}
return sessionId
}
}
And I use it in and SwiftUI View in this way
import SwiftUI
struct ContentView: View {
let ss = ColppyModel()
var body: some View {
Text("Press")
.onTapGesture {
self.getInvoices()
}
}
private func getInvoices() {
let id = ss.getSessionIDFromUserDefaults()
print(id)
ss.getSessionKey()
print(ss.getSessionIDFromUserDefaults())
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
return ContentView()
}
}
The first time I click I get
The second time I click I get
The correct item saved.
How can I do to wait till the data (string in this case) is retrieved from the server and saved to fetch it from the store correctly?
Really I don't quite get the pattern in combine.
Thanks a lot


getSessionKeyhas to be a publisher, whereas in your code, yousinkthe publisher to produce some internal value.