SwiftUI:OnAppear调用部分网络抓取函数失效,Refreshable却正常?
问题分析与解决方案
核心可能原因
1. 并发请求触发目标网站反爬/系统限制
当onAppear同时发起两个请求时,目标网站可能对同一IP的并发请求做了拦截限制,而下拉刷新是单独发起请求,因此能绕过限制正常执行。
2. 单例Scrapper的并发资源冲突
你的Scrapper.shared是单例,如果内部未处理并发请求逻辑(比如共享了URLSession资源、用串行队列处理请求),同时调用两个抓取方法会导致资源抢占,其中一个请求无法正常执行。
3. onAppear执行时机的生命周期问题
SwiftUI的onAppear可能在视图未完全初始化时触发,此时依赖的资源(比如Scrapper的初始化状态)未就绪,导致请求失败;而下拉刷新触发时视图已完全就绪,因此请求正常。
具体排查与解决步骤
第一步:先确认问题本质
打开fetchHistorico中注释的print("scrapeando Historico")语句,运行后观察控制台:
- 如果没有输出:说明
fetchHistorico在onAppear中没被调用,检查视图绑定或触发逻辑 - 如果输出了但没看到
Entro en el historico:打印error的详细信息,定位是网络错误、解析错误还是被网站拦截 - 如果输出了
Entro en el historico:说明请求成功但视图没更新,检查historicoDolar是否为@Published属性(假设ViewModel是ObservableObject)
第二步:针对性解决
解决并发请求限制问题
给两个请求添加延迟,错开发起时间:
.onAppear { fetchDolar() // 延迟0.5秒发起第二个请求,避免并发拦截 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { fetchHistorico() } }
或者用串行队列确保请求顺序执行:
.onAppear { let scrapeQueue = DispatchQueue(label: "com.yourapp.scrape") scrapeQueue.async { self.fetchDolar() scrapeQueue.asyncAfter(deadline: .now() + 0.5) { self.fetchHistorico() } } }
修复Scrapper单例的并发问题
检查Scrapper内部的抓取方法,确保每个请求使用独立的URLSessionTask,如果用了共享队列,改成并发队列(带合适的QoS):
// 示例:Scrapper内部的并发队列设置 class Scrapper { static let shared = Scrapper() private let queue = DispatchQueue(label: "com.scrapper.queue", attributes: .concurrent) func scrappearDolar(completion: @escaping (Result<DolarData, Error>) -> Void) { queue.async { // 执行网络请求与解析,最后回到主线程回调 DispatchQueue.main.async { completion(...) } } } // 同理处理scrapearHistoricoDolar方法 }
替换onAppear为更可靠的task修饰符
Swift 5.5+的.task修饰符更适配异步场景,会在视图就绪后执行,避免生命周期时机问题:
// 回调式写法 .task { fetchDolar() try? await Task.sleep(nanoseconds: 500_000_000) fetchHistorico() } // 推荐改成async/await版本(需要修改Scrapper的方法为异步) func fetchDolar() async { do { let data = try await Scrapper.shared.scrappearDolar() DispatchQueue.main.async { self.dolar = data self.isLoading = false } } catch { DispatchQueue.main.async { self.error = error self.isLoading = false } } } // 然后在task中调用 .task { await fetchDolar() await fetchHistorico() }
内容的提问来源于stack exchange,提问作者Gaston Foncea
相关产品推荐
相关产品推荐

