如何防止 Swift 3 中的嵌套完成块?
How can I prevent nested completion blocks in Swift 3?
我在下面提供的代码中有一系列嵌套完成块。这是因为我需要在后台发出单独的网络请求来抽象数据,以便在下一个方法中使用,它提供了另一个完成块,等等。有没有办法解决?非常感谢任何提示!
func fetchNearbyUsers(forCurrentUser user: User, completionHandler: usersCompletionHandler?) {
self.fetchAllUsers(completionHandler: { (users: [User]) in
ChatProvider.sharedInstance.fetchAllChatrooms(completionHandler: { (chatrooms: [Chatroom]) in
self.validateNewUsers(currentUser: user, users: users, chatrooms: chatrooms, completionHandler: { (validUsers: [User]) in
guard validUsers.isEmpty == false else {
completionHandler?([])
return
}
completionHandler?(validUsers)
})
})
})
}
为什么不调用函数并使用一些布尔值来确保两者都完整。这是一些伪代码
var completeA = false
var completeB = false
func doStuff {
asyncStuffA(stuff {
asyncStuffB(stuff {
}, completion: {
completeB = true
completionHandler()
})
}, completion: {
completeA = true
completionHandler()
})
}
func completionHandler() {
if completeA && completeB {
// Both are complete
completeA = false
completeB = false
}
}
这里的一个选择是使用高阶工厂函数(即 return 其他函数的函数)将块分解为它们自己的函数...
func fetchNearbyUsers(forCurrentUser user: User, completionHandler: @escaping usersCompletionHandler = { _ in }) {
self.fetchAllUsers(completionHandler: self.allUsersFromChatrooms(user: user, completionHandler: completionHandler))
}
func allUsersFromChatrooms(user: User, completionHandler: @escaping usersCompletionHandler) -> ([User]) -> Void {
return { users in
ChatProvider.sharedInstance.fetchAllChatrooms(completionHandler: self.validatedUsersInChatrooms(user: user, users: users, completionHandler: completionHandler))
}
}
func validatedUsersInChatrooms(user: User, users: [User], completionHandler: @escaping usersCompletionHandler) -> ([Chatroom]) -> Void {
return { chatrooms in
self.validateNewUsers(currentUser: user, users: users, chatrooms: chatrooms, completionHandler: completionHandler)
}
}
在上面的代码中,validatedUsersInChatrooms
将 return 一个函数,该函数接受聊天室数组并调用提供的已验证用户的完成处理程序。函数 allUsersFromChatrooms
return 是一个接受用户数组的函数,然后获取聊天室并使用聊天室中经过验证的用户数组调用提供的完成处理程序。
另请注意,我更改了您的 fetchNearbyUsers
函数以接受完成块并默认为不执行任何操作的块,而不是使用可选块。我觉得干净多了。
我在下面提供的代码中有一系列嵌套完成块。这是因为我需要在后台发出单独的网络请求来抽象数据,以便在下一个方法中使用,它提供了另一个完成块,等等。有没有办法解决?非常感谢任何提示!
func fetchNearbyUsers(forCurrentUser user: User, completionHandler: usersCompletionHandler?) {
self.fetchAllUsers(completionHandler: { (users: [User]) in
ChatProvider.sharedInstance.fetchAllChatrooms(completionHandler: { (chatrooms: [Chatroom]) in
self.validateNewUsers(currentUser: user, users: users, chatrooms: chatrooms, completionHandler: { (validUsers: [User]) in
guard validUsers.isEmpty == false else {
completionHandler?([])
return
}
completionHandler?(validUsers)
})
})
})
}
为什么不调用函数并使用一些布尔值来确保两者都完整。这是一些伪代码
var completeA = false
var completeB = false
func doStuff {
asyncStuffA(stuff {
asyncStuffB(stuff {
}, completion: {
completeB = true
completionHandler()
})
}, completion: {
completeA = true
completionHandler()
})
}
func completionHandler() {
if completeA && completeB {
// Both are complete
completeA = false
completeB = false
}
}
这里的一个选择是使用高阶工厂函数(即 return 其他函数的函数)将块分解为它们自己的函数...
func fetchNearbyUsers(forCurrentUser user: User, completionHandler: @escaping usersCompletionHandler = { _ in }) {
self.fetchAllUsers(completionHandler: self.allUsersFromChatrooms(user: user, completionHandler: completionHandler))
}
func allUsersFromChatrooms(user: User, completionHandler: @escaping usersCompletionHandler) -> ([User]) -> Void {
return { users in
ChatProvider.sharedInstance.fetchAllChatrooms(completionHandler: self.validatedUsersInChatrooms(user: user, users: users, completionHandler: completionHandler))
}
}
func validatedUsersInChatrooms(user: User, users: [User], completionHandler: @escaping usersCompletionHandler) -> ([Chatroom]) -> Void {
return { chatrooms in
self.validateNewUsers(currentUser: user, users: users, chatrooms: chatrooms, completionHandler: completionHandler)
}
}
在上面的代码中,validatedUsersInChatrooms
将 return 一个函数,该函数接受聊天室数组并调用提供的已验证用户的完成处理程序。函数 allUsersFromChatrooms
return 是一个接受用户数组的函数,然后获取聊天室并使用聊天室中经过验证的用户数组调用提供的完成处理程序。
另请注意,我更改了您的 fetchNearbyUsers
函数以接受完成块并默认为不执行任何操作的块,而不是使用可选块。我觉得干净多了。