swift - 异步未来承诺在 Swift 5 中不起作用
问题描述
我正在尝试实现对函数 loadUserFromFirebase 的异步调用,并根据用户属性填充并返回一个数组,然后我使用该属性将其写入 firebase 集合。
我正在尝试使用来自 Swift 的 Combine 框架,使用 future 和 promise,但由于某种原因,receiveCompletion 和 receiveValue 没有被调用,因此我从我的异步函数调用中得到一个空数组。
这是我的代码:
var cancellable = Set<AnyCancellable>()
func loadUserFromFirebase(groupUserIds: [String], handler: @escaping ([groupMate]) -> Void) {
var groupmateID = 0
var groupMates : [groupMate] = []
print("groupUserIds: \(groupUserIds)" )
for groupUserUID in groupUserIds {
print("groupUserUID: \(groupUserUID)" )
let future = Future<groupMate, Never> { promise in
self.ref.collection("Users").document(groupUserUID).getDocument(){
(friendDocument, err) in
if let err = err {
print("Error getting documents \(err)")
} else {
// print("friendDocument: \(String(describing: friendDocument?.data()))" )
let groupUsername = (friendDocument?.data()?["username"]) as! String
let groupUID = (friendDocument?.data()?["uid"]) as! String
let groupName = (friendDocument?.data()?["name"]) as! String
let groupPic = (friendDocument?.data()?["imageurl"]) as! String
promise(.success(groupMate(id: groupmateID, uid: groupUID , name: groupName , username: groupUsername, pic: groupPic)))
}
groupmateID += 1
}
}
print("in receiveCompletion")
future.sink(receiveCompletion: { completion in
print("in receiveCompletion")
print(1, completion)
switch completion {
case .failure(let error):
print(3, error)
handler([])
return
case .finished:
break
}
},
receiveValue: {
print("in receiveValue")
groupMates.append($0)
print(groupMates)
handler(groupMates)
}).store(in: &cancellable)
}
}
func creategroup(groupName: String){
addedTogroupUsers.append(self.uid)
print("here111")
loadUserFromFirebase(groupUserIds: addedTogroupUsers) { groupMates in
print("here222")
let groupData: [String: Any] = [
"groupName": "\(groupName)",
"groupmates": groupMates
]
print("here333 \(groupData)")
print("groupMates are \(self.groupMates)")
var groupref: DocumentReference? = nil
groupref = self.ref.collection("groups").addDocument(data: groupData) { err in
if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: \(groupref!.documentID)")
for addedgroupUser in self.addedTogroupUsers {
self.ref.collection("Users").document(addedgroupUser).updateData([
"groups": FieldValue.arrayUnion([groupref!.documentID])
])
}
}
}
print("groupName is \(groupName) and addedTogroup are \(self.addedTogroupUsers)")
}
}
我正在尝试查看 AnyCancellable 是否可行,但由于我使用的是未来承诺的链式数组,因此我不确定如何实现它。请让我知道您将如何解决此问题,以便数组确实被填充,因为文档确实存在并且方法调用中的打印工作但 createGroup 函数中的 groupMates 数组随后会打印一个空数组。谢谢!
编辑:按照建议将 AnyCancallable 与完成处理程序一起添加到代码中
解决方案
处理异步函数可能很棘手。你得到一个空数组,因为你在 loadUserFromFirebase 中返回得太早了。使用旧式闭包尝试这种方法(未经测试):
func loadUserFromFirebase(groupUserIds: [String], handler: @escaping ([groupMate]) -> Void) { // <-- here
var groupmateID = 0
var groupMates : [String] = []
print("groupUserIds: \(groupUserIds)" )
for groupUserUID in groupUserIds {
print("groupUserUID: \(groupUserUID)" )
let future = Future<groupMate, Never> { promise in
self.ref.collection("Users").document(groupUserUID).getDocument(){ (friendDocument, err) in
if let err = err {
print("Error getting documents \(err)")
} else {
print("friendDocument: \(String(describing: friendDocument?.data()))" )
let groupUsername = (friendDocument?.data()?["username"]) as! String
let groupUID = (friendDocument?.data()?["uid"]) as! String
let groupName = (friendDocument?.data()?["name"]) as! String
let groupPic = (friendDocument?.data()?["imageurl"]) as! String
promise(.success(groupMate(id: groupmateID, uid: groupUID , name: groupName , username: groupUsername, pic: groupPic)))
}
groupmateID += 1
}
}
future.sink(receiveCompletion: { completion in
print("in receiveCompletion")
print(1, completion)
switch completion {
case .failure(let error):
print(3, error)
handler([]) // <-- here
return // <-- here
case .finished:
break
}
},
receiveValue: {
print("in receiveValue")
groupMates.append($0)
print(groupMates)
handler(groupMates) // <-- here
})
}
// <-- do not return here
}
func creategroup(groupName: String) {
addedTogroupUsers.append(self.uid)
// -- here wait until you get the data
loadUserFromFirebase(groupUserIds: addedTogroupUsers) { groupMates in
let groupData: [String: Any] = [
"groupName": "\(groupName)",
"groupmates": groupMates // <-- here
]
print("groupMates are \(self.groupMates)")
var groupref: DocumentReference? = nil
groupref = ref.collection("groups").addDocument(data: groupData) { err in
if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: \(groupref!.documentID)")
for addedgroupUser in self.addedTogroupUsers {
self.ref.collection("Users").document(addedgroupUser).updateData([
"groups": FieldValue.arrayUnion([groupref!.documentID])
])
}
}
}
print("groupName is \(groupName) and addedTogroup are \(addedTogroupUsers)")
}
}
请注意,如果您的目标是 ios 15、macos 12,那么使用 swift 5.5 的 async/await/task 功能会获得更好的服务。他们真的很好用。
编辑:试图返回所有结果
func loadUserFromFirebase(groupUserIds: [String], handler: @escaping ([groupMate]) -> Void) {
var groupmateID = 0
var groupMates : [String] = []
print("groupUserIds: \(groupUserIds)" )
var arr: [Future<groupMate, Never>] = [Future<groupMate, Never>]()
var cancellable = Set<AnyCancellable>()
for groupUserUID in groupUserIds {
print("groupUserUID: \(groupUserUID)" )
let future = Future<groupMate, Never> { promise in
self.ref.collection("Users").document(groupUserUID).getDocument(){ (friendDocument, err) in
if let err = err {
print("Error getting documents \(err)")
} else {
print("friendDocument: \(String(describing: friendDocument?.data()))" )
let groupUsername = (friendDocument?.data()?["username"]) as! String
let groupUID = (friendDocument?.data()?["uid"]) as! String
let groupName = (friendDocument?.data()?["name"]) as! String
let groupPic = (friendDocument?.data()?["imageurl"]) as! String
promise(.success(groupMate(id: groupmateID, uid: groupUID , name: groupName , username: groupUsername, pic: groupPic)))
}
groupmateID += 1
}
}
arr.append(future)
}
Publishers.MergeMany(arr)
.collect()
.sink { _ in
print("-----> merging ")
} receiveValue: { value in
print("-----> value: \(value)")
groupMates = value // <--- maybe append?
print(groupMates)
handler(groupMates)
}
.store(in: &cancellable)
}
推荐阅读
- scala - Akka 流 - 如果条件为真则丢弃消息
- python - django 自定义用户模型表单小部件仅适用于电子邮件和姓名字段
- docker - 无法访问 Docker url
- javascript - 自动化在控制台中创建的命令 (DevTools)
- java - 如果文档使用大型 Map 字段,则 Firebase Firestore 查询错误
- tableau-api - 如何计算每月每天、每周和每月的活跃用户数 Tableau
- swift - Firebase 访问规则有问题
- java - 带有 PeerConnection 的 Android WebRTC
- vue.js - 如何在 vuetify 中显示树视图组件
- elasticsearch - 数字范围字段上的 Elasticsearch 聚合