Swift,如何如我所愿地使完成处理程序正常工作?

时间:2019-04-10 18:00:33

标签: swift firebase closures completionhandler

我正在从Firebase中获取用户信息,我的目标是获取一批用户,然后一次在卡堆中一次将它们显示在屏幕上。为此,我使用完成处理程序。但是,我在完成处理程序中的代码会在获取所有用户之前运行。

谢谢您的帮助。

这是我的代码。我希望在完成“ fetchAllUsers”后运行“ fetchOneUser()”:

import numpy as np
import random

from shapely.geometry import Polygon, Point


poly = Polygon([(23.789642, 90.354714), (23.789603, 90.403000), (23.767688, 90.403597),(23.766510, 90.355448)])

def random_points_within(poly, num_points):
    min_x, min_y, max_x, max_y = poly.bounds

    points = []

    while len(points) < num_points:
        random_point = Point([random.uniform(min_x, max_x), random.uniform(min_y, max_y)])
        if (random_point.within(poly)):
            points.append(random_point)

    return points


points = random_points_within(poly,1000)

for p in points:
    print(p.x,",",p.y)

这是fetchAllUser函数:

fetchAllUsers(completion: { message in
   print(message)
   print("FetchOneUser")
   self.fetchOneUser()
})

2 个答案:

答案 0 :(得分:2)

您需要使用DispatchGroup,因为内部调用是异步的

func fetchAllUsers(completion: @escaping (_ message: String) -> Void){
    //User or advertiser?
    Database.database().reference(withPath: "Advertiser").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in

        if snapshot.exists(){
            myAdvertiserVar.advertiser = true
            self.currentUserKind = "Advertiser"
            self.otherUserKind = "Users"
        }
        else{
            self.currentUserKind = "Users"
            self.otherUserKind = "Advertiser"
        }

        // Fetch
        let query = self.ref?.child(self.otherUserKind).queryOrdered(byChild: "email")
        query?.observeSingleEvent(of: .value) {
            (snapshot) in

            let g = DispatchGroup()

            for child in snapshot.children.allObjects as! [DataSnapshot] {
                let id = child.key
                //If Already Accepted, don't fetch

                g.enter()

                Database.database().reference(withPath: self.currentUserKind).child(self.uid).child("Accepted").child(id).observeSingleEvent(of: .value, with: {(accepted) in
                    if accepted.exists(){
                        print("\(id) är redan Accepted")
                    }
                    else{
                        if myAdvertiserVar.advertiser == true{
                            let value = child.value as? NSDictionary
                            let username = value?["Username"] as? String
                            let occupation = value?["Occupation"] as? String
                            let age = value?["Age"] as? String
                            let bio = value?["Bio"] as? String
                            let email = value?["email"] as? String
                            let user = User(id: id, username: username, occupation: occupation, age: age, bio: bio, email: email)
                            self.usersArray.append(user)
                        }
                        else{
                            let value = child.value as? NSDictionary
                            let username = value?["Owner"] as? String
                            let occupation = value?["Location"] as? String
                            let age = value?["Rent"] as? String
                            let bio = value?["About"] as? String
                            let email = value?["email"] as? String
                            let user = User(id: id, username: username, occupation: occupation, age: age, bio: bio, email: email)
                            self.usersArray.append(user)
                        }
                    }

                    g.leave()
                })
            }


            g.notify(queue: .main, execute: {

                print(self.usersArray.count)
                completion("Users list fetched")

            })
        }
    })
}

答案 1 :(得分:1)

基于Firebase documentation:

Firebase使用refrence()方法来获取实时数据库异步根目录的数据库引用。

这意味着获取结果要比for循环花费更多的时间,在这种情况下,您的for循环完成和完成块调用使您退出方法,然后您的请求结果将返回。

您的代码应类似于

var firebaseDatabaseRefrence: DatabaseReference!

override func viewDidLoad() {
   super.viewDidLoad()
   Database.database().reference(withPath: self.currentUserKind)
}

func someMethod() {

  self.firebaseDatabaseRefrence
  .child(self.uid)
  .child("Accepted")
  .child(id).observeSingleEvent(of: .value, with: {(accepted) in 

}