Swift自定义数组追加元素后计数始终为0,求解决方案
问题原因
COLLECTION_USER.document(user).getDocument是异步网络请求,传入的闭包会在请求完成后才执行,而你在循环结束后立刻打印数组计数,这时候所有闭包里的append操作都还没触发,所以数组长度始终为0。
解决方案
方案1:用DispatchGroup跟踪异步任务
通过DispatchGroup标记每个异步任务的开始和结束,等所有请求完成后再处理数组:
func fetchLocations(usersID: [String]){ var annotationsToReturn : [UserAnnotations] = [] let group = DispatchGroup() // 创建调度组 for user in usersID { group.enter() // 标记当前任务开始 COLLECTION_USER.document(user).getDocument { snapshot, err in defer { group.leave() } // 确保任务结束时标记完成,不管成功失败 if err != nil { print("ERROR") return } let data = snapshot?.data() as? [String:Any] ?? [:] // 安全解包,避免强制解包崩溃 guard let latitude = data["latitude"] as? CLLocationDegrees, let longitude = data["longitude"] as? CLLocationDegrees else { print("Invalid location data") return } print("latitude: \(latitude)") annotationsToReturn.append(UserAnnotations(user: User(dictionary: data), coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude))) } } // 等待所有任务完成后执行后续操作 group.notify(queue: .main) { print("count: \(annotationsToReturn.count)") // 这里可以使用填充好的annotationsToReturn做其他业务操作 } }
方案2:用Async/Await(Swift 5.5+)
如果项目支持Swift 5.5及以上版本,用async/await写法更简洁,避免闭包嵌套:
func fetchLocations(usersID: [String]) async { var annotationsToReturn : [UserAnnotations] = [] for user in usersID { do { let snapshot = try await COLLECTION_USER.document(user).getDocument() let data = snapshot.data() as? [String:Any] ?? [:] guard let latitude = data["latitude"] as? CLLocationDegrees, let longitude = data["longitude"] as? CLLocationDegrees else { print("Invalid location data") continue } print("latitude: \(latitude)") annotationsToReturn.append(UserAnnotations(user: User(dictionary: data), coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude))) } catch { print("ERROR: \(error.localizedDescription)") } } print("count: \(annotationsToReturn.count)") // 后续可直接使用annotationsToReturn }
调用该方法时需要在异步上下文里执行:
// 示例:在ViewController的viewDidLoad中调用 override func viewDidLoad() { super.viewDidLoad() Task { await fetchLocations(usersID: ["user_id_1", "user_id_2"]) } }
注意:原代码里的强制解包
latitude as! CLLocationDegrees存在崩溃风险,建议换成上述代码中的guard let安全解包方式。
内容的提问来源于stack exchange,提问作者bruce_blake
相关产品推荐
相关产品推荐

