You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:27:04