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

Alamofire请求后追加数组外部无法访问的问题排查

解决Alamofire异步请求后数组数据无法外部访问的问题

嘿,我一眼就看出问题出在哪了——你搞混了异步操作的执行顺序,而且完成处理程序的调用时机完全错了!

核心问题分析

Alamofire的网络请求是异步执行的:当你调用Alamofire.request()后,代码会立刻继续往下走,不会等网络请求返回结果。

看你最初的代码,外部的UI操作(showCount、displayItemsAroundCurrentLocation)会先于闭包里的数组追加代码执行,这时候establishments数组自然还是空的。

再看你EDIT3里的完成处理程序,你把completion()放在了Alamofire.request()的外面,而不是请求完成的闭包内部!这意味着你还是在网络请求没完成、数组还没更新的时候就触发了回调,结果当然还是0。


正确的修复方案

1. 修正完成处理程序的调用时机

把completion()移到网络请求的闭包里面,确保只有当数据解析完成、数组更新后才通知外部:

func tryingWithCompletionHandler(jsonURLString: String, headers: HTTPHeaders, establishment: Establishment, completion : ()->()) {
    Alamofire.request(jsonURLString, headers: headers).responseJSON { response in
        do {
            // 先做可选值安全处理,避免强制解包崩溃
            guard let data = response.data else {
                print("No data received from request")
                completion()
                return
            }
            
            let establishmentsFromJSON = try JSONDecoder().decode(EstablishmentsFromJSON.self, from: data)
            if !establishmentsFromJSON.establishments.isEmpty {
                // 重要:如果Establishment是struct(值类型),必须创建可变副本再修改
                var mutableEstablishment = establishment
                mutableEstablishment.hygieneRating = establishmentsFromJSON.establishments.first?.RatingValue
                mutableEstablishment.hygieneRatingKey = establishmentsFromJSON.establishments.first?.RatingKey
                mutableEstablishment.hygieneRatingDate = ISO8601DateFormatter().date(from: establishmentsFromJSON.establishments[0].RatingDate)
                mutableEstablishment.hygieneRatingPending = establishmentsFromJSON.establishments.first?.NewRatingPending
                mutableEstablishment.localAuthorityName = establishmentsFromJSON.establishments.first?.LocalAuthorityName
                mutableEstablishment.localAuthorityWebsite = establishmentsFromJSON.establishments.first?.LocalAuthorityWebSite
                mutableEstablishment.localAuthorityEmail = establishmentsFromJSON.establishments.first?.LocalAuthorityEmailAddress
                
                self.establishments.append(mutableEstablishment)
            }
            // 不管有没有解析到数据,都要调用completion
            completion()
        } catch {
            print("Parsing error occurred:")
            print(error)
            // 出错时也要调用completion,避免回调永远不执行
            completion()
        }
    }
    // 原来这里的completion()要彻底删掉!
}

2. 调用时切换到主线程更新UI

Alamofire的responseJSON闭包默认在后台线程执行,更新UI必须回到主线程:

self.tryingWithCompletionHandler(jsonURLString: jsonURLString, headers: headers, establishment: establishment, completion: {
    DispatchQueue.main.async {
        self.showCount(self.establishments.count)
        print("place count: \(self.establishments.count)")
        self.arView.displayItemsAroundCurrentLocation(currentLocation: currentPlace, establishments: self.establishments)
    }
})

3. 额外注意:值类型的坑

如果Establishment是struct(值类型),直接修改传入的establishment对象是没用的——因为值类型传递的是副本,你修改的只是闭包里的临时副本,不会影响原对象。所以上面的代码里创建了mutableEstablishment可变副本,修改后再追加到数组。如果是class(引用类型),这一步可以省略,但也要注意线程安全。


为什么之前的尝试没用?

  • 你一开始的代码没考虑异步顺序,UI操作先执行了
  • 完成处理程序的错误在于completion()调用太早,没等异步请求完成就触发了回调

只要把completion()移到闭包内部,确保数组更新后再通知外部,问题就迎刃而解了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:43:31