斯威夫特,如何让完成处理程序按我的意愿工作?
Posted
技术标签:
【中文标题】斯威夫特,如何让完成处理程序按我的意愿工作?【英文标题】:Swift, How to Get Completion Handler working as I Wish? 【发布时间】:2019-04-10 18:00:32 【问题描述】:我正在从 Firebase 获取用户信息,我的目标是获取一批用户,然后在卡片堆栈中一次一个地显示它们。为此,我使用完成处理程序。但是,我在完成处理程序中的代码在所有用户的获取完成之前运行。
感谢您的帮助。
这是我的代码。我希望在“fetchAllUsers”完成后运行“fetchOneUser()”:
fetchAllUsers(completion: message in
print(message)
print("FetchOneUser")
self.fetchOneUser()
)
这里是 fetchAllUser 函数:
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
for child in snapshot.children.allObjects as! [DataSnapshot]
let id = child.key
//If Already Accepted, don't fetch
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)
)
print(self.usersArray.count)
completion("Users list fetched")
)
【问题讨论】:
尝试从 for 循环中创建数据库引用,Database.database().reference 将异步连接到实时数据库,当 for 循环完成时返回结果,如果这有帮助,请通知我,我无法测试,因为Firebase 限制伊朗语 【参考方案1】:你需要使用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")
)
)
【讨论】:
【参考方案2】:基于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
【讨论】:
以上是关于斯威夫特,如何让完成处理程序按我的意愿工作?的主要内容,如果未能解决你的问题,请参考以下文章