oty*_*tin 9 async-await firebase swift google-cloud-firestore
我只是想要一个示例,说明如何async/await使用 Swift 新的并发功能来重写常见的 Firestore 侦听器方法,如下所示。
func listen(for user: User, completion: (Result<CurrentUser, Error>) -> Void) {
db.collection("Users")
.document(user.uid)
.addSnapshotListener(includeMetadataChanges: true) { document, error in
if let error = error {
completion(.failure(.networkError)
} else {
guard let document = document else {
completion(.failure(.operationFailure)
return
}
do {
guard let profile = try document.data(as: Profile.self, with: .estimate) else {
completion(.failure(.operationFailure)
return
}
completion(CurrentUser(user, profile: profile))
} catch {
completion(.failure(.operationFailure)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
好的,就像我在评论中所说的那样,我认为这不是异步/等待的正确用例。Async/Await 更适合异步函数,您将在其中收到单个响应。例如返回某个值的 REST api。
顺便说一句,Firestore 函数.getDocument()现在有 async/await 替代方案。
然而,addSnapshotListener随着时间的推移,它会返回多个值并一遍又一遍地调用回调函数。
不过,我们可以用它来做的就是将其变成一个组合发布器。
在这里,我创建了一个小FirestoreSubscription结构,您可以使用它来订阅文档路径......
import Combine
import FirebaseFirestore
import FirebaseFirestoreSwift
struct FirestoreSubscription {
static func subscribe(id: AnyHashable, docPath: String) -> AnyPublisher<DocumentSnapshot, Never> {
let subject = PassthroughSubject<DocumentSnapshot, Never>()
let docRef = Firestore.firestore().document(docPath)
let listener = docRef.addSnapshotListener { snapshot, _ in
if let snapshot = snapshot {
subject.send(snapshot)
}
}
listeners[id] = Listener(document: docRef, listener: listener, subject: subject)
return subject.eraseToAnyPublisher()
}
static func cancel(id: AnyHashable) {
listeners[id]?.listener.remove()
listeners[id]?.subject.send(completion: .finished)
listeners[id] = nil
}
}
private var listeners: [AnyHashable: Listener] = [:]
private struct Listener {
let document: DocumentReference
let listener: ListenerRegistration
let subject: PassthroughSubject<DocumentSnapshot, Never>
}
Run Code Online (Sandbox Code Playgroud)
该subscribe函数返回一个AnyPublisher<DocumentSnapshot, Never>(所以目前它不处理任何错误。
我还创建了一个FirestoreDecoder可以解码DocumentSnapshot为我自己的Codable类型的...
import Firebase
struct FirestoreDecoder {
static func decode<T>(_ type: T.Type) -> (DocumentSnapshot) -> T? where T: Decodable {
{ snapshot in
try? snapshot.data(as: type)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个非常简单的 Firestore 文档...
我们将从该文档中解码一个结构......
struct LabelDoc: Codable {
let value: String?
}
Run Code Online (Sandbox Code Playgroud)
现在,ViewController我可以订阅该文档路径并解码并将其设置到标签上......
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
var cancellables: Set<AnyCancellable> = []
struct SubscriptionID: Hashable {}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
FirestoreSubscription.subscribe(id: SubscriptionID(), docPath: "labels/title")
.compactMap(FirestoreDecoder.decode(LabelDoc.self))
.receive(on: DispatchQueue.main)
.map(\LabelDoc.value)
.assign(to: \.text, on: label)
.store(in: &cancellables)
}
}
Run Code Online (Sandbox Code Playgroud)
这只是一个快速示例项目,因此可能有更好的方法来执行此操作,但现在我可以更新 Firestore 中的值,它将立即在屏幕上更新
您甚至可以将该订阅包装到一个可以在多个地方使用的函数中。
| 归档时间: |
|
| 查看次数: |
5388 次 |
| 最近记录: |