SwiftUI中含UIImage的自定义对象数组排序失败问题排查
问题分析与解决方案
核心错误1:DispatchGroup的leave()位置错误
你当前的代码里,group.leave()直接写在了异步的getData闭包外面,这意味着循环每遍历一个元素,刚调用group.enter()就立刻执行leave(),DispatchGroup会认为所有任务都已完成,notify回调会提前触发——这时候图片还在异步加载中,imageCollection里的元素还没填满,排序自然不会生效。
正确的做法是把group.leave()放到getData的闭包内部,确保只有当图片加载完成(无论成功失败)后,才通知DispatchGroup这个任务结束。
核心错误2:UI更新未在主队列执行
@Published修饰的变量更新需要在主队列完成,因为SwiftUI的视图刷新依赖主线程。你当前的notify用了DispatchQueue.global(),即使排序成功,视图也不会同步更新。
其他需要修正的细节
- 每次调用
getAllImages时,先清空imageCollection,避免重复添加旧数据; - 确保
time字符串的格式是可正确比较的(比如yyyy-MM-dd HH:mm:ss),如果是类似9:00和10:00的格式,字符串比较会出现"10:00" < "9:00"的错误结果。
修正后的完整代码
func getAllImages() { let storageRef = Storage.storage().reference() // 清空旧数据 self.imageCollection = [] guard !student.imageRefCollection.isEmpty else { return } let group = DispatchGroup() for image in self.student.imageRefCollection { group.enter() let fileRef = storageRef.child(image.url) fileRef.getData(maxSize: 5*128*128) { [weak self] imageData, error in defer { // 无论加载成功或失败,都必须调用leave(),避免DispatchGroup挂起 group.leave() } guard let self = self, error == nil, let imageData = imageData else { return } let fetchedImage = UIImage(data: imageData) ?? UIImage() let imageToAdd = ImageCollectionModel( image: fetchedImage, taskNr: image.taskNr, time: image.time ) self.imageCollection.append(imageToAdd) } } group.notify(queue: .main) { [weak self] in guard let self = self else { return } // 在主队列排序并更新数组,触发视图刷新 self.imageCollection.sort { $0.time < $1.time } } }
额外建议
如果time的字符串格式无法保证排序正确性,建议将ImageModel和ImageCollectionModel中的time字段改为Date类型,存储时转成ISO8601字符串存入Firebase,取出时再转成Date,这样排序会更准确且不易出错。
内容的提问来源于stack exchange,提问作者FreddanF1
相关产品推荐
相关产品推荐

