别让慢请求覆盖新选择:用 AI + SwiftUI task(id:) 管住筛选结果

别让慢请求覆盖新选择:用 AI + SwiftUI task(id:) 管住筛选结果

这一技教你让 AI 用 SwiftUI task(id:) 管理远程搜索和筛选请求,在用户快速切换时取消旧任务,并用可控慢请求验收旧结果、旧错误和清空输入不会串台。

先看你遇到的是哪种问题

用户先选「全部」,又马上切到「未读」,页面却短暂显示了「全部」的结果,甚至把「未读」的错误提示盖掉。只要筛选、搜索或分段选择会触发网络请求,这个问题就值得查。
它通常不是界面画错了,而是前一个请求还没结束,后一个请求已经开始。谁最后返回,谁就把结果写进页面。慢网络下,旧请求反而更容易赢。
如果数据已经在内存里,只是对本地数组做过滤,不需要 task(id:)。这招针对的是「用户的选择变化,会触发异步工作」的页面,例如远程搜索、分类切换、排序切换和按账户状态加载数据。

这招具体做什么

SwiftUI 的 task(id:) 会在视图出现时执行异步任务,也会在指定的 id 变化时重新执行。SwiftUI 的官方说明将它定义为「视图出现或指定值变化时执行的任务入口」1
把用户当前的筛选值放进 id,就等于告诉页面:「筛选变了,上一轮工作不再是当前工作。」SwiftUI 会取消上一轮任务并启动新任务;这个行为也可以在 Hacking with Swift 的 Xcode 16.4 实践说明中核对到2
但「取消」不是强行抹掉已经返回的结果。Swift 的任务取消是协作式的,任务本身要检查取消状态;Task.checkCancellation() 会在任务已取消时抛出错误3。所以这次改动的重点有两处:让筛选值成为任务 ID,让结果写回前确认任务还有效。

让 AI 先改一处最小范围

在 AI 编码工具里,先选中「筛选控件 + 结果列表 + 当前加载函数」所在的视图,再贴下面这段指令。不要让 AI 一次重写整个页面。
请只修改当前 SwiftUI 结果页,不改变现有的筛选 UI、数据模型和成功态布局。
  1. 找到会因 queryselectedFilter 变化而发起异步请求的代码,把请求放到 .task(id:) 中,id 使用真正触发请求的那个值;如果有两个值共同决定请求,用一个 Equatable 的查询条件值承载它们。
  2. 异步请求返回后,先调用 try Task.checkCancellation(),再把结果写入页面状态。
  3. 单独吞掉取消错误,不要在用户快速切换筛选时显示「加载失败」;真正的网络错误仍要保留当前页面的错误提示。
  4. 不要把删除、支付、提交订单等有副作用的动作放进这个任务;只处理读取和展示结果。
  5. 给我列出改动的文件、任务 ID 使用的状态、取消错误的处理位置,以及仍需要我手动验收的边界。
AI 可能会给出类似下面的核心结构。这里的 query 只是示例,实际项目可能叫 selectedCategorysortOptionrequestKey
.task(id: query) {
    do {
        let newItems = try await search(query: query)
        try Task.checkCancellation()
        items = newItems
    } catch is CancellationError {
        return
    } catch {
        errorMessage = "加载失败,请重试"
    }
}
如果页面同时依赖「关键词 + 分类 + 排序」,不要只把关键词放进 id。让 AI 先把这三个值组成一个可比较的查询条件,再用它作为 id,否则用户只改分类时可能不会启动正确的新任务。

PM 自己怎么验收

先让 AI 加一个仅用于调试的假数据开关:给旧筛选故意加更长延迟,给新筛选加更短延迟。这样不用等真实接口偶发变慢,也能稳定复现问题。验收时记录「触发值、预期结果、实际结果」三列,按下面顺序走:
  1. 输入或选择「A」,立刻切到「B」。最终列表只能是 B,不能先出现 A 再停在 A。
  2. 连续切换「A → B → C」。页面标题、筛选标签和列表内容都要对应 C。
  3. 先触发一个会失败的 A,再切到正常的 B。A 的失败不能覆盖 B,也不能在 B 页面闪出错误提示。
  4. 清空关键词或切回「全部」。页面要回到产品定义的初始结果,不能残留上一轮筛选。
  5. 请求进行中离开页面,再回来。旧页面任务不应继续把结果写进已经离开的页面。
  6. 关闭调试假延迟后再测一次真实接口,确认加载中、成功、空结果和网络失败仍各自有清楚的界面状态。
第 1 步是这项改动的核心验收。如果旧请求比新请求更晚返回,页面仍停在 A,说明 AI 只改了调用位置,没有真正处理取消或取消后的状态写回。

今天就做这一小步

找一个「切换后偶尔显示旧结果」的远程列表,不要先改搜索框样式。把当前触发请求的状态写在纸上或便签里,例如「关键词、分类、排序」,然后把这三个值交给 AI 组成任务 ID,再用可控慢请求跑完上面的第 1、3、4 步。
验收通过后,你会得到一个明确的产品判断:用户看到的结果,确实对应他最后一次选择。至于本地过滤、分页加载和提交类动作,继续使用各自的处理方式,不要为了统一写法全部塞进 task(id:)

Contenido relacionado

  • Inicia sesión para comentar.
More from this channel