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

Swift中全局变量bank在viewDidLoad值为0,JSON序列化时为1的问题

问题根源:异步执行顺序搞的鬼!

嘿,这个坑我踩过好多次!你遇到的情况几乎可以肯定是异步任务的执行顺序导致的——咱们来一步步拆解到底发生了什么:

1. 先理清代码的执行流程

你定义的全局变量var bank = Int()默认值是0,然后调用getProfile()方法。但这里的关键是:getProfile()里的JSON解析操作,大概率是在异步任务里完成的(比如网络请求的回调、后台队列的处理)。

举个最典型的场景,你的getProfile()可能是这样写的:

func getProfile() {
    // 假设这是一个异步网络请求(比如URLSession的dataTask)
    URLSession.shared.dataTask(with: someProfileURL) { data, response, error in
        guard let data = data else { return }
        // 解析JSON
        let jsonResult = try! JSONSerialization.jsonObject(with: data) as! [String: Any]
        let banks = jsonResult["banks"] as! Int
        print(banks) // 这里打印出1
        self.bank = banks // 赋值操作在异步闭包里
    }.resume()
}

这时候代码的执行顺序是:

  • 视图加载时,viewDidLoad()先执行,你调用了getProfile()
  • getProfile()发起异步任务(比如网络请求),但主线程不会等它完成,直接继续往下走,执行print(bank)——这时候bank还是默认的0
  • 等异步任务完成(比如网络请求拿到数据),才会执行闭包里的代码,把bank赋值为1,但这时候viewDidLoad()里的打印早就跑完了!

2. 怎么验证这个猜想?

你可以在两个地方加打印日志,看看输出顺序:

// 在getProfile的赋值处加打印
self.bank = banks
print("✅ 赋值完成!当前bank值:\(self.bank)")

// 在viewDidLoad里加打印
override func viewDidLoad() {
    super.viewDidLoad()
    getProfile()
    print("📱 viewDidLoad执行中,当前bank值:\(bank)")
}

运行后你会发现,viewDidLoad的打印会先出现(显示0),过一会儿才会出现赋值完成的打印(显示1)——这就实锤了顺序问题!

3. 怎么解决?

核心思路是:等异步任务完成后,再去使用bank变量,这里给你两种常用的方案:

方案一:用闭包回调

改造getProfile(),添加一个完成回调,在异步任务结束后通知主线程:

func getProfile(completion: @escaping (Int) -> Void) {
    URLSession.shared.dataTask(with: someProfileURL) { data, _, error in
        guard let data = data, error == nil else {
            completion(0) // 出错时返回默认值
            return
        }
        do {
            let jsonResult = try JSONSerialization.jsonObject(with: data) as! [String: Any]
            let banks = jsonResult["banks"] as! Int
            // 切回主线程更新变量或UI
            DispatchQueue.main.async {
                completion(banks)
            }
        } catch {
            completion(0)
        }
    }.resume()
}

然后在viewDidLoad()里这样用:

override func viewDidLoad() {
    super.viewDidLoad()
    getProfile { [weak self] bankValue in
        self?.bank = bankValue
        print("现在bank的值是:\(self?.bank ?? 0)")
        // 所有需要用到bank的逻辑都放在这里
    }
}

方案二:用Swift的Async/Await(Swift 5.5+)

如果你的项目支持Swift 5.5及以上,用异步等待会更简洁:

// 把getProfile改成异步函数
func getProfile() async throws -> Int {
    let (data, _) = try await URLSession.shared.data(from: someProfileURL)
    let jsonResult = try JSONSerialization.jsonObject(with: data) as! [String: Any]
    return jsonResult["banks"] as! Int
}

然后在viewDidLoad()里用Task调用:

override func viewDidLoad() {
    super.viewDidLoad()
    // 启动一个异步任务
    Task {
        do {
            let bankValue = try await getProfile()
            self.bank = bankValue
            print("现在bank的值是:\(self.bank)")
            // 后续依赖bank的操作放在这里
        } catch {
            print("获取数据出错:\(error)")
        }
    }
}

不管哪种方案,核心都是确保你在bank被正确赋值之后,再去使用它,而不是在异步任务还没完成时就急于打印或使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:41:39