iOS开发:viewDidAppear未刷新Firebase图片 回调嵌套优化
- 线程调度不是你当前问题的核心诱因:你已经在图片下载的completion中切主线程刷新UI,线程问题概率极低,异常根因集中在两点:
- 数据时序错乱:Firebase Realtime Database默认开启本地持久化缓存,拉取用户资料时如果没有指定从服务端获取最新值,会优先返回本地缓存的旧数据。出现文本更新正常、图片URL为旧值的情况,本质是缓存返回的快照中,文本字段已经更新,但图片URL字段未及时同步,导致加载了旧图。
- 图片请求竞态覆盖:从编辑页返回profile页时,旧的图片下载任务未被取消,当新的图片下载任务发出后,旧任务的completionHandler可能晚于新任务执行,将已经赋值的新图覆盖为旧图。
- 对应修复操作:
- 拉取关键用户资料时,显式指定数据源为服务端,避免拿到缓存的时序错乱值:调用Database的数据获取接口时传入
source: .server,强制拉取最新的用户信息。 - 给每个UIImageView绑定当前正在加载的请求标识:下载完成回调触发时,先比对回调里的标识和UIImageView当前绑定的标识是否一致,不一致直接丢弃回调结果,不做UI赋值,避免旧请求覆盖新图。
- 取消所有无关联的图片下载任务:当页面从编辑页返回、重新拉取用户资料时,先把之前未完成的图片下载任务全部取消,避免竞态。
- 拉取关键用户资料时,显式指定数据源为服务端,避免拿到缓存的时序错乱值:调用Database的数据获取接口时传入
多步异步操作的代码结构优化
- 你当前遇到的回调嵌套过深、上传完成前无法返回的问题,本质是把所有异步流程的完成时机和页面跳转强绑定了,完全可以通过流程拆分降低耦合,按上手难度从低到高可选择以下方案:
- 方案1:用
DispatchGroup拆分可并行的任务,减少嵌套层数
头像和banner的上传过程无相互依赖,可并行执行,不需要等第一个图片上传完成再传第二个,既缩短整体上传时长,也能减少嵌套层级:let uploadGroup = DispatchGroup() var avatarURL: String? var bannerURL: String? var uploadError: Error? // 上传头像任务 uploadGroup.enter() uploadAvatar(selectedAvatar) { result in defer { uploadGroup.leave() } switch result { case .success(let url): avatarURL = url case .failure(let error): uploadError = error } } // 上传banner任务,和头像上传并行执行 uploadGroup.enter() uploadBanner(selectedBanner) { result in defer { uploadGroup.leave() } switch result { case .success(let url): bannerURL = url case .failure(let error): uploadError = error } } // 两个上传都完成后的统一处理 uploadGroup.notify(queue: .main) { guard uploadError == nil else { self.showError(uploadError!) return } // 拿到两个图片的下载URL后即可直接pop回profile页 self.navigationController?.popViewController(animated: true) // 后台执行Database的资料保存,不需要等它完成再跳转 self.saveUserProfileToDatabase(avatarURL: avatarURL!, bannerURL: bannerURL!) } - 方案2:适配async/await语法,彻底消除回调嵌套
项目部署版本支持iOS15及以上时,可将原来带completionHandler的Firebase接口通过withCheckedThrowingContinuation封装为async方法,主流程代码完全线性,无需处理嵌套闭包,错误可统一在catch块中处理,可读性远优于嵌套回调。
- 方案1:用
- 关于“上传完成前无法返回页面”的优化:完全不需要等所有上传、数据库写入操作完成再允许用户返回。用户点击提交后,先将本地编辑的图片、文本暂存,立刻pop回profile页,再在后台队列执行上传Storage、写入Database的操作;profile页本身通过Firebase的实时监听节点变化,数据更新后会自动触发UI刷新,既不会卡住用户交互,也能保证数据最终一致。
内容的提问来源于stack exchange,提问作者De Santa Michell
相关产品推荐
相关产品推荐

