Ios Firebase完成下载后如何直接执行代码?

Ios Firebase完成下载后如何直接执行代码?,ios,swift,firebase,firebase-realtime-database,Ios,Swift,Firebase,Firebase Realtime Database,我有一些代码需要在Firebase完成下载任务后立即执行。问题是,此代码总是在下载完成之前运行 if currentVersionNumber < newVersionNumber { print("Feed: button donwloading cards") //self.databaseButton.setTitle("Downloading New Cards...", for: .normal) ref.o

我有一些代码需要在Firebase完成下载任务后立即执行。问题是,此代码总是在下载完成之前运行

if currentVersionNumber < newVersionNumber {
            print("Feed: button donwloading cards")
            //self.databaseButton.setTitle("Downloading New Cards...", for: .normal)
            ref.observe(.value, with: { snapshot in
                print("Feed: Checking for new cards from firebase")
                for item in snapshot.children {
                    // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
                    cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
                        if (error != nil) {
                            // Uh-oh, an error occurred!
                            print("Feed: error occured")
                            print(error)
                        } else {
                            // Data for "images/island.jpg" is returned
                            cards.imageName = data!
                            print("Feed: downloaded \(cards.name)")
                        }
                    }
                    // add to updated list of cards

                    updateCards.append(cards);
                }
            })

        } else {
             print("Feed: cards are up to date. \(currentVersionNumber)")
        }

    })
如果currentVersionNumberVoid in
如果(错误!=nil){
//哦,发生了一个错误!
打印(“提要:发生错误”)
打印(错误)
}否则{
//返回“images/island.jpg”的数据
cards.imageName=数据!
打印(“提要:下载\(cards.name)”)
}
}
//添加到更新的卡片列表中
updateCards.追加(卡片);
}
})
}否则{
打印(“提要:卡是最新的。\(currentVersionNumber)”)
}
})

这段代码从Firebase数据库下载我想要的项目,但在完成之前,它将运行其后的任何代码。我该如何做才能选择在下载完成后立即执行代码块?

这是因为Firebase的所有更新都发生在后台线程中,而您的代码在主线程上执行。要处理此调用,请在函数中调用firebase方法,该函数具有一个闭包,在firebase下载完成后立即调用该闭包

例如:

视图中加载

override func viewDidLoad() {

   super.viewDidLoad()

   fetchData {

       //do whatever action you wish to perform on download completion
       mainTableView.reloadData()
   }
}

func fetchData(andOnCompletion completion:@escaping ()->()){

   ref.observe(.value, with: { snapshot in
            print("Feed: Checking for new cards from firebase")
            for item in snapshot.children {
                // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
                cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
                    if (error != nil) {
                        // Uh-oh, an error occurred!
                        print("Feed: error occured")
                        print(error)
                    } else {
                        // Data for "images/island.jpg" is returned
                        cards.imageName = data!
                        print("Feed: downloaded \(cards.name)")
                    }
                }
                // add to updated list of cards

                updateCards.append(cards);
            }
         //call the block when done processing          
     completion()
  })
}

这是因为Firebase的所有更新都发生在后台线程中,并且您的代码在主线程上执行。要处理此调用,请在函数中调用firebase方法,该函数具有一个闭包,在firebase下载完成后立即调用该闭包

例如:

视图中加载

override func viewDidLoad() {

   super.viewDidLoad()

   fetchData {

       //do whatever action you wish to perform on download completion
       mainTableView.reloadData()
   }
}

func fetchData(andOnCompletion completion:@escaping ()->()){

   ref.observe(.value, with: { snapshot in
            print("Feed: Checking for new cards from firebase")
            for item in snapshot.children {
                // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
                cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
                    if (error != nil) {
                        // Uh-oh, an error occurred!
                        print("Feed: error occured")
                        print(error)
                    } else {
                        // Data for "images/island.jpg" is returned
                        cards.imageName = data!
                        print("Feed: downloaded \(cards.name)")
                    }
                }
                // add to updated list of cards

                updateCards.append(cards);
            }
         //call the block when done processing          
     completion()
  })
}

这些网络请求是异步运行的,因此在网络请求完成时,它们之后的任何代码都将继续运行

您应该将updateCards.append(卡片)移动到内部闭包中,以便在第二个闭包完成之前不会调用它,然后,如果您有其他代码需要在完成时运行,您可以将其移动到此函数中,或者使用带有完成处理程序的闭包,以确保在运行更多代码之前完成所有网络请求,这些代码依赖于响应

getCardData { [weak self] in
// do whatever you need to do after completion
}

func getCardData(_ completion: () -> ()) {
print("Feed: button donwloading cards")
//self.databaseButton.setTitle("Downloading New Cards...", for: .normal)
ref.observe(.value, with: { snapshot in
    print("Feed: Checking for new cards from firebase")
    for item in snapshot.children {
        // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
        cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
            if (error != nil) {
                // Uh-oh, an error occurred!
                print("Feed: error occured")
                print(error)
                completion() // this is where you would normally throw an error or have a closure that accepts an optional error you would pass in to know it failed
            } else {
                // Data for "images/island.jpg" is returned
                cards.imageName = data!
                print("Feed: downloaded \(cards.name)")
                updateCards.append(cards);
                completion()// now you know all network requests are complete
            }
        }
     }
  })
}

这些网络请求是异步运行的,因此在网络请求完成时,它们之后的任何代码都将继续运行

您应该将updateCards.append(卡片)移动到内部闭包中,以便在第二个闭包完成之前不会调用它,然后,如果您有其他代码需要在完成时运行,您可以将其移动到此函数中,或者使用带有完成处理程序的闭包,以确保在运行更多代码之前完成所有网络请求,这些代码依赖于响应

getCardData { [weak self] in
// do whatever you need to do after completion
}

func getCardData(_ completion: () -> ()) {
print("Feed: button donwloading cards")
//self.databaseButton.setTitle("Downloading New Cards...", for: .normal)
ref.observe(.value, with: { snapshot in
    print("Feed: Checking for new cards from firebase")
    for item in snapshot.children {
        // Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
        cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
            if (error != nil) {
                // Uh-oh, an error occurred!
                print("Feed: error occured")
                print(error)
                completion() // this is where you would normally throw an error or have a closure that accepts an optional error you would pass in to know it failed
            } else {
                // Data for "images/island.jpg" is returned
                cards.imageName = data!
                print("Feed: downloaded \(cards.name)")
                updateCards.append(cards);
                completion()// now you know all network requests are complete
            }
        }
     }
  })
}

通过在下载中添加if语句来解决我的问题,该语句检查附加到updateCards的卡数是否等于快照中的卡数。感谢两位回答这个问题的人,因为我也使用了completion()方法,很高兴我去了解这个我不知道存在的概念

通过在下载中添加一条if语句来解决我的问题,该语句检查updateCards中附加的卡数是否等于快照中的卡数。感谢两位回答这个问题的人,因为我也使用了completion()方法,很高兴我去了解这个我不知道存在的概念

我看到一个答案被添加,但我不知道他们会有多近。如果我不花点时间,我会删除它,但我想两个例子比一个好。只是提醒一下,你没有将updateCards.append移动到内部闭包。这似乎对我不起作用,因为它要求在完成下载之前完成。我看到添加了一个答案,但我不知道它们会有多接近。如果我不花点时间,我会删除它,但我想两个例子比一个好。只是提醒一下,你没有将updateCards.append移动到内部闭包。这似乎对我不起作用,因为它在下载完成之前调用完成。两个答案似乎都不起作用,在下载完成之前调用完成。另一个答案似乎起作用,在下载完成之前调用完成