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

URLSession异步请求后数组为空问题及解决方法咨询

问题原因

确实和异步执行方式有关。URLSession.shared.dataTask是异步任务,它会在后台线程发起网络请求,不会阻塞主线程。你调用oRedHatCVEs.jsonDataRequest()后,代码会立刻执行txtvJSON.text = ...,这时候网络请求还没完成,arrCVE还没被填充,所以显示元素数为0。

解决方案

方法1:闭包回调(最通用的异步处理方式)

修改请求函数,添加完成回调闭包,在数据加载完成后通知ViewController更新UI:

// 调整请求函数,增加完成回调
func jsonDataRequest(completion: @escaping ([CVE]?, Error?) -> Void) {
    guard let urlObj = URL(string: "https://access.redhat.com/hydra/rest/securitydata//cve.json?after=2022-12-26") else {
        completion(nil, NSError(domain: "InvalidURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "URL格式错误"]))
        return
    }
    
    URLSession.shared.dataTask(with: urlObj) { (data, response, error) in
        if let error = error {
            completion(nil, error)
            return
        }
        
        guard let data = data else {
            completion(nil, NSError(domain: "NoData", code: -2, userInfo: [NSLocalizedDescriptionKey: "未获取到数据"]))
            return
        }
        
        do {
            // 直接解码为数组,无需遍历重新创建实例
            let cveList = try JSONDecoder().decode([CVE].self, from: data)
            self.arrCVE = cveList
            completion(cveList, nil)
        } catch {
            completion(nil, error)
        }
    }.resume()
}

ViewController中调用时,通过闭包获取数据并更新UI:

let oRedHatCVEs = RedHatCVEs()
oRedHatCVEs.jsonDataRequest { [weak self] cveList, error in
    guard let self = self else { return }
    if let error = error {
        print("请求失败:\(error.localizedDescription)")
        return
    }
    // 必须在主线程更新UI
    DispatchQueue.main.async {
        self.txtvJSON.text = "Array elements: \(oRedHatCVEs.arrCVE.count)"
    }
}

方法2:Combine框架(iOS 13+适用)

如果项目支持iOS 13及以上,可用Combine处理异步数据流:

import Combine

class RedHatCVEs {
    var arrCVE : [CVE] = []
    var cancellables = Set<AnyCancellable>()
    
    func jsonDataRequest() -> AnyPublisher<[CVE], Error> {
        guard let urlObj = URL(string: "https://access.redhat.com/hydra/rest/securitydata//cve.json?after=2022-12-26") else {
            return Fail(error: NSError(domain: "InvalidURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "URL格式错误"])).eraseToAnyPublisher()
        }
        
        return URLSession.shared.dataTaskPublisher(for: urlObj)
            .map(\.data)
            .decode(type: [CVE].self, decoder: JSONDecoder())
            .receive(on: DispatchQueue.main)
            .handleEvents(receiveOutput: { [weak self] cveList in
                self?.arrCVE = cveList
            })
            .eraseToAnyPublisher()
    }
}

ViewController中调用:

let oRedHatCVEs = RedHatCVEs()
oRedHatCVEs.jsonDataRequest()
    .sink(receiveCompletion: { completion in
        if case .failure(let error) = completion {
            print("请求失败:\(error.localizedDescription)")
        }
    }, receiveValue: { [weak self] cveList in
        self?.txtvJSON.text = "Array elements: \(cveList.count)"
    })
    .store(in: &oRedHatCVEs.cancellables)

额外优化建议

  • 去掉代码中遍历重新创建CVE实例的逻辑,直接self.arrCVE = jsonCVE即可完成数组填充,避免不必要的性能消耗。
  • 永远不要强制解包urlObj!,用guard let做安全校验,防止URL格式错误导致崩溃。
  • 所有UI更新操作必须放在主线程执行,避免界面卡顿或异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:25:18