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

SwiftUI onAppear内嵌套网络请求无法获取数据问题

问题原因

列表无法加载数据由4个核心问题导致:

  • 异步时序错误:网络请求是异步非阻塞逻辑,调用getDataModelApi()后代码不会等待请求返回,会立刻执行后续的for循环。此时一级接口还未响应,存储子链接的数组为空,循环不会执行,根本不会触发子接口数据拉取。
  • 属性引用错误:getDataModelApi()解码后赋值的是Api类的modelApiLink属性,但视图层遍历的是modelApiLink.models属性,两个属性完全不对应,就算一级请求返回也拿不到子链接列表。
  • 数据覆盖问题:如果getData(url:)逻辑和getDataModelApi()完全一致,会将解码结果整体赋值给models数组,后返回的子接口数据会覆盖之前的内容,最终数组只会保留最后一个接口的返回值,无法聚合所有业务数据。
  • 冗余实例问题:创建两个独立的Api实例拆分逻辑没有必要,反而增加了跨实例状态同步的成本,额外的命名不规范(类型名用小驼峰model、页面名拼写错误detiles)也容易触发隐性问题。
修复方案

推荐使用Swift原生async/await语法控制异步流程(适配iOS15+),从根源避免回调地狱与时序混乱,同时修正逻辑问题:

  1. 重构Api类,统一管理网络逻辑,消除重复代码,修正数据存储逻辑
// 注意:Swift类型名使用大驼峰命名规范
struct Model: Identifiable, Decodable {
    let id: Int
    let title: String
    let url: String
}

class Api : ObservableObject{
    // 存储一级接口返回的子API链接
    @Published var apiLinks: [Model] = []
    // 存储所有子接口返回的聚合业务数据
    @Published var businessModels: [Model] = []
    
    // 统一管理鉴权信息,避免重复代码
    private let token = "38|Xxxxxxx"
    private func buildAuthorizedRequest(for urlString: String) -> URLRequest? {
        guard let url = URL(string: urlString) else { return nil }
        var request = URLRequest(url: url)
        request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        return request
    }
    
    // 拉取一级接口的子链接列表
    private func fetchApiLinks() async {
        guard let request = buildAuthorizedRequest(for: APIgetURL.demo) else { return }
        do {
            let (data, _) = try await URLSession.shared.data(for: request)
            let decodedLinks = try JSONDecoder().decode([Model].self, from: data)
            await MainActor.run {
                self.apiLinks = decodedLinks
            }
        } catch {
            print("拉取子链接失败: ", error)
        }
    }
    
    // 拉取单个子接口的业务数据
    private func fetchSingleBusinessData(url: String) async {
        guard let request = buildAuthorizedRequest(for: url) else { return }
        do {
            let (data, _) = try await URLSession.shared.data(for: request)
            let decodedModel = try JSONDecoder().decode(Model.self, from: data)
            await MainActor.run {
                // 如需去重可在此处加判断逻辑
                self.businessModels.append(decodedModel)
            }
        } catch {
            print("拉取子接口\(url)数据失败: ", error)
        }
    }
    
    // 对外暴露的统一加载方法:先拉链接,再并行拉取所有业务数据
    func loadAllContent() async {
        // 等待子链接拉取完成后再执行后续逻辑
        await fetchApiLinks()
        // 用任务组并行拉取所有子接口数据,比串行请求速度更快
        await withTaskGroup(of: Void.self) { group in
            for link in apiLinks {
                group.addTask {
                    await self.fetchSingleBusinessData(url: link.url)
                }
            }
        }
    }
}
  1. 简化视图层逻辑,只保留一个Api实例,用.task修饰符处理异步加载
struct VideoViewAll : View {
    // 只需要一个视图模型实例即可,无需创建多个
    @StateObject private var viewModel = Api()

    var body: some View {
        VStack {
            ScrollView(.vertical, showsIndicators: false) {
                ForEach(viewModel.businessModels) { item in
                    HStack {
                        // 修正原拼写错误detiles -> Details
                        NavigationLink(destination: Details(model: item)) {
                            Spacer()
                            VStack(alignment: .trailing, spacing: 15) {
                                Text(item.title)
                            }
                            .padding(.trailing, 5)
                        }
                    }
                }
            }
        }
        // 视图加载时自动触发异步请求,视图销毁时自动取消任务,避免内存泄漏
        .task {
            await viewModel.loadAllContent()
        }
    }
}

// 详情页
struct Details: View {
    let model: Model
    var body: some View {
        Text(model.title)
    }
}

若需要兼容iOS14及更早版本无法使用async/await,可通过给网络方法增加逃逸闭包回调的方式控制时序:在getDataModelApi的请求完成回调中遍历链接列表,再触发子接口请求;同时修正属性引用错误,将子接口返回的数据追加到models数组而非直接覆盖即可。

内容的提问来源于stack exchange,提问作者3sr0 store

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:27:14