是否可以在多个ViewController中快速创建串行队列

时间:2020-06-15 14:23:07

标签: swift firebase concurrency google-cloud-firestore

我有一系列的ViewControllers,每个都将数据上传到Firebase。我想知道是否可以创建一个串行队列,以确保它们按照显示视图控制器的顺序进行上传。我是否需要创建一个委托方法来执行类似的操作?

我的ViewController如下所示

VC 1:

class VC1: UIViewController{

   func nextVC(_ data: Data){
      db.collection("collection")
        .document("Document").setData([
           "data1": data
        ]){ err in
           if let err = err {
              print("Error writing document: \(err)")
           } else {
              print("Document successfully written!")
           }
       }
       self.performSegue(withIdentifier: K.firstSegue, sender: self)
   }
}

VC 2:

class VC2: UIViewController{

   func nextVC(_ data: Data){
      db.collection("collection")
        .document("Document").updateData([
           "data2": data
        ]){ err in
           if let err = err {
              print("Error writing document: \(err)")
           } else {
              print("Document successfully written!")
           }
       }
       self.performSegue(withIdentifier: K.secondSegue, sender: self)
   }
}

VC 3:

class VC3: UIViewController{

   func nextVC(_ data: Data){
      db.collection("collection")
        .document("Document").updateData([
           "data3": data
        ]){ err in
           if let err = err {
              print("Error writing document: \(err)")
           } else {
              print("Document successfully written!")
           }
       }
   }
}

编辑:进行澄清

我遇到的问题是,当我到达第三个视图控制器时,我会得到一个错误,即我尝试更新的文档不存在。我认为,通过将所有三个Firebase调用添加到DispatchQueue中,可以避免此问题。这确实奏效,但是我在视图控制器之间的滞后时间遇到了问题。我希望ViewControllers将他们的数据添加到队列中,以串行方式上传到Firebase,以便他们按正确的顺序加载,并在后台进行,以便它不会影响用户界面。

3 个答案:

答案 0 :(得分:3)

Firebase任务本身是异步的,因此创建队列除了保证按顺序启动外,不能保证其他任何事情。但这仅是从主线程启动它们而已。而且,您不能保证会按顺序收到或按顺序完成它们。

如果确实必须按顺序运行这些命令,则必须在先前请求的完成处理程序中移动segue的启动。例如,考虑:

func nextVC(_ data: Data){
    db.collection("collection").document("Document").setData(["data1": data]) { err in
        if let err = err {
            print("Error writing document: \(err)")
        } else {
            print("Document successfully written!")
        }
    }
    self.performSegue(withIdentifier: K.firstSegue, sender: self)
}

将其更改为

func nextVC(_ data: Data){
    db.collection("collection").document("Document").setData(["data1": data]) { err in
        if let err = err {
            print("Error writing document: \(err)")
        } else {
            print("Document successfully written!")
            self.performSegue(withIdentifier: K.firstSegue, sender: self)
        }
    }
}

还有其他模式(异步自定义Operation子类,合并等),但这是最简单的方法。

答案 1 :(得分:2)

就单个串行队列问题而言,只需说出您通常会说的话即可,即

let queue = DispatchQueue(label:"myqueue")

...但是在正确的地方说出 。为什么地方很重要?因为在Swift中,位置决定了寿命和范围。您想要一个所有其他代码都可以看到的队列(全局范围),该队列将一直存在(生存期)。

有两种主要方法可以做到这一点。一种是说声明在任何类声明之外。例如,将其放在import语句之后的 AppDelegate.swift 文件的顶部。这使它成为纯全局。在您的应用程序代码中到处都有简单的名称。

另一种方法是使它成为某个类或其他类型的static let。这赋予它全局范围,同时也很好地命名它。例如:

struct GlobalQueues { // or this could be an enum
    static let firebaseQueue = DispatchQueue(label:"myqueue") 
}

结果是您可以在应用程序代码中的任何地方引用GlobalQueues.firebaseQueue,这比纯全局名称更好。它没有功能上的区别,但它阐明了这个东西是什么以及它的“住处”。

答案 2 :(得分:0)

我找到了解决问题的方法。由于我在更新文档时遇到很多错误,因此我决定一次上传所有信息,方法是将所有必需的信息传递到最后一个vc并上传。