跳转到正文
YGJoon 技术博客

SwiftUI 详情页并发加载:请求竞态与导航状态保留

发布于:
·699 字 · 约 2 分钟·作者:
通过独立资料区块、请求代次和可替换依赖,处理详情页并发请求及导航返回后的重复加载。
SwiftUI 详情页并发加载:请求竞态与导航状态保留文章封面
目录

示例代码均为匿名化改写,用于说明模式;数据类型和错误呈现可按页面需求扩展。

详情页通常组合多种数据

资料页可能同时加载主资料、相关条目、收藏状态、相册与分享信息。若其中一个辅助列表加载失败,不应让整页都变为空白;主资料和次级区块可以分别拥有加载与错误状态。

将外部请求作为可替换依赖注入后,测试可以控制返回时间。主资料与项目列表可以并行请求,但每次加载都要记录请求代次。用户切换到另一条资料后,旧响应即使晚到也不能覆盖新内容。

快速切换资料时,请求代次可以阻止旧结果覆盖新状态;取消仍是协作式的,底层请求应检查 Task.isCancelled 并尽早退出。

导航返回与重复加载

@MainActor
final class DetailModel<Profile: Sendable, Related: Sendable> {
    private(set) var profile: Profile?
    private(set) var related: [Related] = []
    private var generation = 0

    func load(
        id: UUID,
        fetchProfile: @Sendable (UUID) async throws -> Profile,
        fetchRelated: @Sendable (UUID) async throws -> [Related]
    ) async throws {
        generation += 1
        let requestGeneration = generation

        async let loadedProfile = fetchProfile(id)
        async let loadedRelated = fetchRelated(id)
        let (nextProfile, nextRelated) = try await (loadedProfile, loadedRelated)

        guard generation == requestGeneration else { return }
        profile = nextProfile
        related = nextRelated
    }
}

还要区分系统重建视图和用户主动刷新:前者可以复用已有快照,后者应创建新请求代次,避免把过期数据当成刷新结果。

SwiftUI 的导航返回可能再次触发页面任务。如果相同资料已经完整加载,可以复用现有状态,避免页面跳闪和滚动位置重置;用户主动重试仍应重新加载。

完成标记只能在所有必要请求结束后更新。请求取消或主要资料失败时,不能错误地把页面标记为已完整加载。

路由状态和业务数据分开

详情页的弹层、子页面目标、确认框属于暂态路由状态;主资料和操作结果属于业务状态。把两者分开放置,可减少大型视图的条件分支,也让页面流程测试不需要构造完整 UI。

异步回归检查


分享这篇文章:


相关文章

上一篇
iOS Keychain 会话隔离:请求快照与迟到响应处理
下一篇
iOS 图片缓存与对象存储:actor 并发去重和尺寸变体