我一直在我的iOS Swift应用中使用以下代码:
class ProfileController
{
func remove(pid: String, completion: @escaping ErrorCompletionHandler)
{
guard let uid = self.uid else
{
completion(Errors.userIdentifierEmpty)
return
}
let db = Firestore.firestore()
let userDocument = db.collection("profiles").document(uid)
let collection = userDocument.collection("profiles")
let document = collection.document(pid)
document.delete()
{
error in
completion(error)
}
}
}
设备在线时,一切正常。 delete
调用的完成处理程序已正确执行。但是,当我离线时,我注意到只要离线,就不会执行完成处理程序。我一回到网上,就会立即调用完成处理程序。
我不想等到用户重新联机(这可能要花一辈子的时间),所以我稍微更改了代码并添加了ListenerRegistration
:
class ProfileController
{
func remove(pid: String, completion: @escaping ErrorCompletionHandler)
{
guard let uid = self.uid else
{
completion(Errors.userIdentifierEmpty)
return
}
let db = Firestore.firestore()
let userDocument = db.collection("profiles").document(uid)
let collection = userDocument.collection("profiles")
let document = collection.document(pid)
var listener: ListenerRegistration?
listener = document.addSnapshotListener(includeMetadataChanges: false)
{
snapshot, error in
listener?.remove() // Immediately remove the snapshot listener so we only receive one notification.
completion(error)
listener = nil
}
document.delete()
}
}
尽管这很好,但我不确定这是否是正确的方法。我已经在线阅读了可以在实时场景中使用快照侦听器的信息,这并不是我真正想要的(或我所需要的)。
这是正确的方法还是其他(更好)的方法?我只想得到一次通知(因此我添加了includeMetadataChanged属性并将其设置为false)。一旦完成处理程序被调用一次,我还将删除ListenerRegistration
。
如果第一种方法在脱机时无法正常工作-这种方法的用例是什么?在我将整个代码库更改为使用侦听器之前,有什么方法可以在设备离线时执行第一种方法的完成处理程序?
TL; DR :第二种实现效果很好,我只是不确定这是否是设备离线时接收通知的正确方法。
答案 0 :(得分:1)
如果第一种方法在脱机时无法正常工作-这种方法的用例是什么?
这取决于您所说的“正常工作”的意思。您观察到的行为完全符合预期。直到在服务器上注册写操作后,它们才能“完成”。
但是,所有写入(不是事务)实际上都是在到达服务器之前在本地提交的。这些本地更改将最终在将来的某个时刻与服务器同步,即使该应用被终止并重启。更改不会丢失。只要用户继续启动应用程序,您就可以依靠更改的同步最终使其到达服务器-这就是您所期望的。您可以在documentation中阅读有关脱机持久性的更多信息。
如果您需要了解先前的更改是否已同步,则没有简便的方法来确定应用程序是否已被终止并重新启动。如果您知道所写文档的ID,则可以尝试查询该数据,并且可以检查文档的元数据以找出数据源(缓存或服务器)。但是最后,您真的应该相信,更改将在最早的方便时与服务器同步。
如果您的用例需要更多粒度的信息,请file a feature request with Firebase support。