将替换 .compactMap 与自定义 .decode 结合起来

Combine replace `.compactMap` with custom `.decode`

我创建了一个 AnyPublisher 用于订阅 Firestore 文档,输出类型是 DocumentSnapshot。

我运行是这样的...

firestoreSubscription.subscribe(MyHashable(), "/user/1234567890")
    .compactMap { try? [=10=].data(as: UserDoc.self }

这个return的类型是<UserDoc, Never>,我想保留。

这行得通,但我认为如果我可以在 Publisher 上使用 .decode 功能使其更像 Combiney,那会很酷。

所以我创建了这个...

public struct FirestoreDecoder: TopLevelDecoder {
    public init() {}
    
    public typealias Input = DocumentSnapshot
    
    public func decode<T>(_ type: T.Type, from: DocumentSnapshot) throws -> T where T : Decodable {
        try! from.data(as: type)!
    }
}

所以现在我试试这个...

environment.firestoreSubscription.subscribe(userSubscriptionID, "/user/\(state.userID)")
    .decode(type: UserDoc.self, decoder: FirestoreDecoder())

但是...TopLevelDecoder 抛出而不是 returning nil。我想知道,是否可以丢弃 throws 并默认返回到我在使用 .decode 方法时使用的紧凑地图解决方案?

或者...我应该继续使用 .compactMap 吗?

还有... .decode 上的 throw 会结束发布者吗?

will the throw on the .decode end the publisher

是的,这将导致流失败 - 如果您订阅 Firestore 上的更改,这可能不是您想要的

您可以使用 Combine 的 catch 运算符来处理流中的故障

使用你的例子,忽略你会发现的失败和 return 一个 Empty 发布者。

environment.firestoreSubscription.subscribe(userSubscriptionID, "/user/\(state.userID)")
    .decode(type: UserDoc.self, decoder: FirestoreDecoder())
    .catch{ _ in Empty<UserDoc, Never>().eraseToAnyPublisher() }

好的,将 FirestoreDecoder 更改为...

import Firebase

public struct FirestoreDecoder {
    public static func decode<T>(_ type: T.Type) -> (DocumentSnapshot) -> T? where T: Decodable {{
        try? [=10=].data(as: type)
    }}
}

我能够做到...

firestoreSubscription.subscribe(MyHashable(), "/user/1234567890")
    .compactMap(FirestoreDecoder.decode(UserDoc.self))

这与我最初的相似,但将对 Firestore 的依赖推到了单独的模块中。