Swift中XMLParser同步加载XML正常 异步URLSession方法不生效问题咨询
问题根因分析
1. 赋值时机错误
XMLParser(contentsOf: url)是同步阻塞接口,调用后会等待XML下载、解析全部完成才会向下执行后续代码,所以你在RadioPlayer初始化中调用podcastParser.loadData()后直接赋值podcasts = podcastParser.podcasts时,解析已经完成,能拿到正确数据。
而URLSession.dataTask是异步接口,调用task.resume()后会立刻返回执行后续代码,此时网络请求还在后台执行,XML还未下载解析,赋值时拿到的是空数组,后续解析完成后也没有机制更新RadioPlayer的podcasts属性,所以界面无变化。
2. 观察器使用错误
@ObservedObject是SwiftUI视图专用的属性包装器,只能在View结构体中使用,你在ObservableObject类型的RadioPlayer类中用它修饰podcastParser,根本无法收到PodcastParser内部属性的更新通知。
修复方案
第一步:确保PodcastParser属性正确
确认PodcastParser遵守ObservableObject协议,且存储解析结果的数组加@Published修饰:
import Foundation import Combine class PodcastParser: NSObject, XMLParserDelegate, ObservableObject { // 解析结果必须用@Published修饰,变化时才会发出通知 @Published var podcasts: [Podcast] = [] @Published var loading = false // 你原有XMLParser的代理实现,确保解析到的item正确添加到podcasts数组 }
第二步:修正异步加载逻辑
放开你注释的dataTask代码,补充错误处理、避免循环引用:
func loadData() { self.loading = true guard let url = URL(string: "THERIGHTURLTOXMLFILE") else { print("Error on create URL to read file") self.loading = false return } let task = URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in guard let self = self else { return } // 错误处理 if let error = error { print("请求失败: \(error.localizedDescription)") DispatchQueue.main.async { self.loading = false } return } guard let httpRes = response as? HTTPURLResponse, httpRes.statusCode == 200, let data = data else { print("响应无效或无数据") DispatchQueue.main.async { self.loading = false } return } // 主线程解析XML DispatchQueue.main.async { self.podcasts.removeAll() let parser = XMLParser(data: data) parser.delegate = self parser.parse() self.loading = false } } task.resume() }
第三步:修正RadioPlayer的观察逻辑
用Combine订阅PodcastParser的podcasts变化,自动同步到自身的podcasts属性:
import Combine class RadioPlayer: ObservableObject { private let podcastParser = PodcastParser() // 存储订阅,避免被自动释放 private var cancellables = Set<AnyCancellable>() @Published var podcasts: [Podcast] = [] @Published var podcastIndex = 0 init() { // 订阅podcastParser的podcasts变化,自动更新自身的podcasts podcastParser.$podcasts .receive(on: DispatchQueue.main) .assign(to: &$podcasts) // 启动加载 podcastParser.loadData() } }
内容的提问来源于stack exchange,提问作者Leff
相关产品推荐
相关产品推荐

