Aim:
I would like to know what is the preferred way to decode using Combine to parse only valid records and not provide default values for failures.
Questions:
- I get the desired output, but is this a reasonable approach or is there a better way to do it ?
- I couldn't find something like
tryDecode
(liketryMap
), or could other more suitable operator be used to achieve this ?
Based on the WWDC example, I have modified it slightly.
Code:
I am returning nil
when parsing fails and then use compactMap
not sure if there is a better way to do it.
import Foundation
import Combine
//Model
public struct CarRecord : Codable {
var name : String
var doors : Int
}
//Notification
extension Notification.Name {
public static let didPost = Notification.Name("didPost")
}
func postNotifications() {
let d1 = #"{"name":"aaa","doors":2}"#.data(using: .utf8)! //Good record
let d2 = #"{"name":"ccc"}"#.data(using: .utf8)! //Faulty record
let d3 = #"{"name":"ddd","doors":5}"#.data(using: .utf8)! //Good record
let datas = [d1, d2, d3]
for data in datas {
NotificationCenter.default.post(name: .didPost,
object: nil,
userInfo: ["Car" : data])
}
}
//Combine
let cancellable = NotificationCenter.default.publisher(for: .didPost)
.compactMap { $0.userInfo?["Car"] as? Data }
.flatMap { data in
Just(data)
.decode(type: CarRecord.self, decoder: JSONDecoder())
.map { Optional($0) } //added
.catch { _ in
Just(nil) //modified
}
}
.compactMap { $0 } //added
.sink {
print("attempt: \($0)")
}
postNotifications()
Output:
attempt: CarRecord(name: "aaa", doors: 2)
attempt: CarRecord(name: "ddd", doors: 5)