2017-06-24 86 views
1

我很難理解爲什麼這個代碼在用戶被附加到一個類別之前正在執行完成塊。Swift:只有在執行代碼後,我如何才能調用此完成塊?

首先,我試圖獲取該類別。每個類別都有一個用戶標識數組,這些用戶標識被循環訪問,從我的數據庫中的一個單獨位置獲取用戶。

這裏是火力地堡數據:

["Category 1": { 
title = lifestyle; 
users =  (
    ESKYpDMPiHW34, 
    HJ8ItJDoExZMQ, 
    1WDnoPy4PeQkm 
); 
}, "Category 2": { 
title = fitness; 
users =  (
    ESKYpDMPiHW3, 
    HJ8ItJDoExZM, 
    1WDnoPy4PeQk 
); 
}, "Category 3": { 
title = health; 
}] 

這裏是我的代碼:

class func fetchFeaturedUsers(completion: @escaping ([UserCategory]) -> Swift.Void) { 
    var categories = [UserCategory]() 

    let dbRef = Database.database().reference().child("categories") 
    dbRef.observeSingleEvent(of: .value, with: { (snap) in 

     if let dict = snap.value as? [String: Any] { 
      for (_, value) in dict { 

       if let category = value as? [String:Any] { 

        let title = category["title"] as? String 
        let newCategory = UserCategory(title: title?.capitalized, users: [User]()) 
        categories.append(newCategory) 

        if let users = category["users"] as? [String] { 
         for id in users { 
          User.fetchUser(userId: id, completion: { (newUser) in 
           newCategory.users?.append(newUser) 
          }) 
         } 
        } 
       } 
      } 
     } 
     DispatchQueue.main.async { 
      completion(categories) 
     } 
    }) 
} 
+0

您是否嘗試過將它添加到'DispatchQueue.main.async'中? –

+0

是的,沒有任何變化。完成仍然被稱爲第一。 –

+1

我認爲你的問題是'User.fetchUser'調用是異步的,所以在任何調用返回之前,取回所有用戶的循環完成。所有你的代碼都會執行,然後完成塊被調用。 –

回答

1

的問題是,你的User.fetchUser方法是在另一個線程正在做的異步調用。爲了解決這個你可以創建一個DispatchGroup,將等到所有來電呼叫completion這樣之前完成:

class func fetchFeaturedUsers(completion: @escaping ([UserCategory]) -> Swift.Void) { 
    var categories = [UserCategory]() 
    let dispatchGroup = DispatchGroup() 

    let dbRef = Database.database().reference().child("categories") 
    dbRef.observeSingleEvent(of: .value, with: { (snap) in 

     if let dict = snap.value as? [String: Any] { 
      for (_, value) in dict { 

       if let category = value as? [String:Any] { 

        let title = category["title"] as? String 
        let newCategory = UserCategory(title: title?.capitalized, users: [User]()) 
        categories.append(newCategory) 

        if let users = category["users"] as? [String] { 
         for id in users { 
          dispatchGroup.enter() 
          User.fetchUser(userId: id, completion: { (newUser) in 
           newCategory.users?.append(newUser) 
           dispatchGroup.leave() 
          }) 
         } 
        } 
       } 
      } 
     } 

     dispatchGroup.notify(queue: DispatchQueue.global(qos: .background)){ 
      completion(categories)     
     } 
    }) 
} 

您可以在documentation閱讀更多關於DispatchGroup。

+0

這就是我的想法,並且我嘗試了相同的代碼,但在dispatchGroup.leave()上發生了(lldb)崩潰。這是因爲有不成比例的leave()和enter()? –

+0

@CharlesBlack是的,我剛剛編輯了我的代碼,'enter'必須在'for'循環中,對此抱歉。 –

+0

太棒了!這是我需要的。欣賞它。 –

相關問題