2017-12-27 1064 views
1

我試圖從observeSingleEvent獲得某個名爲City的子節點,但我在試圖將其拉入主線程中時出現問題。我使用了完成處理程序和調度調用的組合,但我不確定我在做什麼錯誤,除了在異步方面沒有那麼好。在viewDidLoad我試圖從setupSavedLocations函數追加我的密鑰,並將它返回給savedLocations我覺得我很接近。我錯過了什麼?不知道如何在異步調用之外追加數組

編輯:淨度上的問題

import UIKit 
import Firebase 

class SavedLocationsViewController: UIViewController { 

    var userID: String? 
    var savedLocations: [String] = [] 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupSavedLocations() { (savedData) in 
      DispatchQueue.main.async(execute: { 
       self.savedLocations = savedData 
       print("inside", self.savedLocations) 
      }) 
     } 
     print("outside",savedLocations) 
    } 

     func setupSavedLocations(completion: @escaping ([String]) ->()) { 
     guard let user = userID else { return } 
     let databaseRef = Database.database().reference(fromURL: "https://************/City") 
     var dataTest : [String] = [] 
     databaseRef.observeSingleEvent(of: .value, with: {(snapshot) in 
      let childString = "Users/" + user + "/City" 
      for child in snapshot.children { 
       let snap = child as! DataSnapshot 
       let key = snap.key 
       dataTest.append(key) 
      } 
      completion(dataTest) 
     }) 
    } 

樣本輸出

outside [] 
inside ["New York City", "San Francisco"] 
+0

您的代碼沒有顯示任何錯誤。無論如何,只需稍加觀察,您可能需要在'main.async'前面指定'savedLocations':'self.savedLocations = savedData DispatchQueue.main.async'中的setupSavedLocations(){(savedData),然後如果需要刷新一些組件,例如:'UITableView',你必須在'main.async'裏面執行它 –

+0

在main.async之外有什麼理由?這是否意味着無法在主線程上使用我的savedLocation? – LampPost

+0

你的意思是「試圖將其拉入主線程的問題」?如果您引用的是「外部」打印語句未列出位置,那是因爲它在setupSavedLocations完成之前正在調用。它是異步的,所以它在運行時不會阻止你的viewDidLoad。 – ghostatron

回答

1

setupSavedLocations的調用是異步的,並且需要運行較長時間比它的CPU來完成viewDidLoad這就是爲什麼你的數據沒有被顯示。你也可以從你的輸出中注意到,在inside之前調用outside表明這一點。處理這種情況的正確方法是向用戶顯示他們需要等待IO調用,然後在下面顯示相關信息時向他們顯示相關信息。

class SavedLocationsViewController: UIViewController { 

    var myActivityIndicator: UIActivityIndicatorView? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupSavedLocations() { (savedData) in 
      DispatchQueue.main.async(execute: { 
       showSavedLocations(locations: savedData) 
      }) 
     } 
     // We don't have any data here yet from the IO call 
     // so we show the user an indicator that the call is 
     // being made and they have to wait 

     let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)   
     myActivityIndicator.center = view.center   
     myActivityIndicator.startAnimating() 
     self.view.addSubview(myActivityIndicator) 
     self.myActivityIndicator = myActivityIndicator 
    } 

    func showSavedLocations(locations: [String]) { 
     // This function has now been called and the data is passed in. 
     // Indicate to the user that the loading has finished by 
     // removing the activity indicator 
     myActivityIndicator?.stopAnimating() 
     myActivityIndicator?.removeFromSuperview() 

     // Now that we have the data you can do whatever you want with it here 
     print("Show updated locations: \(locations)") 
    } 
相關問題