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

使用Alamofire获取数据时函数执行顺序异常导致返回数组为空

Alamofire 5.0 请求后数组为空、执行顺序异常问题

问题表现

初学Alamofire 5.0时遇到代码执行顺序不符合预期的问题:数据拉取、变量赋值流程未按书写顺序执行,最终获取到的天气预报数组为空。
相关代码实现如下:

数据拉取函数

func fetchForecast() {
        let url = "http://api.weatherapi.com/v1/current.json"
        
        for city in cities {
            let parameters: [String: String] = ["key": apiKey,
                                                "q": city,
                                                "aqi": "no"]
            
            AF.request(url, parameters: parameters)
              .validate()
              .responseDecodable(of: CurrentForecast.self) { (response) in
                  switch response.result {
                  case .success(let value):
                      print("Before appending")
                      self.currentForecasts.append(value)
                      print("After appending")
                  case .failure(let error):
                      print("Failed with error: \(error)")
                  }
                  print("Before printing self.currentForecasts")
                  print(self.currentForecasts)
                  print("After printing self.currentForecasts")
              }
        }
    }

控制器存储属性

var currentForecasts = [CurrentForecast]()
var cities: [String] = ["Moscow", "London"]

生命周期调用逻辑

override func viewDidLoad() {
        super.viewDidLoad()
        print("Before fetch")
        fetchForecast()
        print("After fetch")
        print("Before printing currentForecasts")
        print(currentForecasts)
        print("After printing currentForecasts")
    }

实际运行控制台输出和预期不符:调用fetchForecast后立刻打印天气预报数组得到空值,所有网络请求的响应回调都在fetchForecast执行结束后才触发,输出如下:

Before fetch
After fetch
Before printing currentForecasts
[]
After printing currentForecasts
Before appending
After appending
Before printing self.currentForecasts
[Forecast for London]
After printing self.currentForecasts
Before appending
After appending
Before printing self.currentForecasts
[Forecast for London, Forecast for Moscow]
After printing self.currentForecasts

问题根因

这是异步编程的通用特性,和Alamofire本身逻辑无关:
网络请求属于异步任务,发起请求后不会阻塞当前线程等待结果返回。
调用AF.request时,系统仅会将网络任务提交给后台线程调度,当前主线程会继续向下执行:首先跑完fetchForecast内的循环(循环逻辑仅完成请求发起动作,不会等待响应),接着执行viewDidLoad中fetchForecast()调用后的打印代码——此时网络请求仍在后台运行,尚未拿到返回数据,currentForecasts自然为空。
等后台网络任务拿到服务器响应后,才会执行responseDecodable传入的闭包逻辑,向数组中追加数据,这也是闭包内所有打印内容都出现在日志末尾的原因。
额外注意:并发发起的多个网络请求返回顺序不固定,不会严格遵循循环内的城市排列顺序,日志中先返回London结果、后返回Moscow结果就是这个特性的体现,业务逻辑不要依赖请求返回顺序。

修复方案

不要在发起请求的代码行之后立刻读取currentForecasts的值,等请求完成后再执行数据处理、UI刷新逻辑,两种常用实现方式:

  • 方式一:用DispatchGroup监听所有请求完成
    适合需要等所有城市数据全部加载完再统一刷新UI的场景,修改fetchForecast方法加入分组调度逻辑,所有请求结束后触发回调:
    func fetchForecast(completion: @escaping () -> Void) {
        let url = "http://api.weatherapi.com/v1/current.json"
        let requestGroup = DispatchGroup()
        
        for city in cities {
            requestGroup.enter() // 每发起一个请求,分组计数+1
            let parameters: [String: String] = ["key": apiKey,
                                                "q": city,
                                                "aqi": "no"]
            
            AF.request(url, parameters: parameters)
              .validate()
              .responseDecodable(of: CurrentForecast.self) { (response) in
                  switch response.result {
                  case .success(let value):
                      self.currentForecasts.append(value)
                  case .failure(let error):
                      print("Request failed: \(error)")
                  }
                  requestGroup.leave() // 单个请求结束(无论成功失败),分组计数-1
              }
        }
        
        // 所有请求全部执行完后,在主线程触发回调
        requestGroup.notify(queue: .main) {
            completion()
        }
    }
    
    调用时在回调内处理后续逻辑:
    override func viewDidLoad() {
        super.viewDidLoad()
        fetchForecast { [weak self] in
            // 走到这里所有请求已经完成,数组有值
            print(self?.currentForecasts ?? [])
            // 执行刷新列表、更新UI等后续逻辑
        }
    }
    
  • 方式二:单请求返回后即时处理
    不需要等所有数据加载完的场景,可以直接在单个请求的成功闭包内,将拿到的单条天气预报数据同步更新到对应UI位置,不用等待全部请求结束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:51:25