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

Swift中如何正确并行加载两个JSON数据以填充TableView?

关于并行加载两个JSON数据源的实践建议

嘿,这个问题问得很关键——咱们先聊聊你当前做法的潜在问题,再分享几种更靠谱的并行加载方案。

当前做法的风险点

首先得明确:如果你的loadJSONOne和loadJSONTwo里面的网络请求是同步执行的(比如用了阻塞式的网络调用),那这绝对是糟糕的实践——主线程会被彻底卡住,UI完全无法响应,甚至可能触发系统的看门狗机制导致APP崩溃。

如果你的网络请求是异步的(比如用了URLSession.dataTask这类默认在后台队列执行的API),那当前写法不会阻塞主线程,但依然有优化空间:比如任务的统一管理、更清晰的错误处理,以及确保UI更新的线程安全。

更合适的并行加载方式

1. 用GCD并发队列管理(兼容iOS 13及以下)

如果你的项目需要兼容较低版本iOS,可以用GCD的并发队列来明确将网络请求放在后台执行,完成后切回主线程更新UI:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 创建一个自定义并发队列,统一管理JSON加载任务
    let jsonLoadingQueue = DispatchQueue(label: "com.yourApp.json.loader", attributes: .concurrent)
    
    // 并行启动两个加载任务
    jsonLoadingQueue.async {
        self.loadJSONOne()
    }
    
    jsonLoadingQueue.async {
        self.loadJSONTwo()
    }
}

func loadJSONOne() {
    guard let url = URL(string: "https://your-first-api-url.com") else { return }
    
    URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
        guard let self = self else { return }
        
        // 处理错误
        guard let data = data, error == nil else {
            DispatchQueue.main.async {
                // 在这里更新UI提示加载失败,比如显示错误标签
            }
            return
        }
        
        // 解析JSON
        do {
            let model = try JSONDecoder().decode(YourFirstModel.self, from: data)
            DispatchQueue.main.async {
                // 更新第一个TableView的数据并刷新
                self.firstTableViewData = model
                self.firstTableView.reloadData()
            }
        } catch {
            DispatchQueue.main.async {
                // 处理解析错误
            }
        }
    }.resume()
}

// loadJSONTwo的实现逻辑和上面一致,对应第二个TableView
func loadJSONTwo() {
    // ... 类似的异步网络请求+解析+主线程UI更新逻辑
}

2. 用Async/Await + Task Group(iOS 15+ 推荐)

如果你的项目已经适配iOS 15及以上,那async/await结合Task Group是最现代、最简洁的并行方案,代码可读性和可维护性都更好:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 启动一个后台Task来并行执行两个加载任务
    Task {
        await withTaskGroup(of: Void.self) { group in
            // 添加第一个加载任务到组里
            group.addTask {
                await self.loadJSONOne()
            }
            // 添加第二个加载任务,和第一个并行执行
            group.addTask {
                await self.loadJSONTwo()
            }
        }
    }
}

func loadJSONOne() async {
    guard let url = URL(string: "https://your-first-api-url.com") else { return }
    
    do {
        // 异步获取数据
        let (data, _) = try await URLSession.shared.data(from: url)
        // 异步解析JSON
        let model = try JSONDecoder().decode(YourFirstModel.self, from: data)
        // 切回主线程更新UI(用MainActor确保线程安全)
        await MainActor.run {
            self.firstTableViewData = model
            self.firstTableView.reloadData()
        }
    } catch {
        await MainActor.run {
            // 处理加载或解析错误,给用户反馈
        }
    }
}

// loadJSONTwo的实现逻辑类似
func loadJSONTwo() async {
    // ... 异步网络请求+解析+主线程UI更新逻辑
}

核心注意点

  • 绝对避免主线程同步网络请求:这是iOS开发的大忌,会直接摧毁用户体验。
  • UI更新必须在主线程:不管用哪种方案,更新TableView或其他UI元素时,一定要确保代码在主线程执行(GCD的DispatchQueue.main.async或者MainActor.run)。
  • 错误处理不能少:每个请求都要单独处理失败情况,避免一个请求失败导致另一个无法正常执行,同时给用户清晰的加载状态反馈(比如ActivityIndicator)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:08:46