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

如何从主视图调用Mappable类变量?返回值为空问题

解决异步网络请求后数据为空的问题

嘿,我看你遇到的是个很典型的异步请求时序问题,再加上数据传递环节的缺失,导致调用lowerData.companyName时拿到空值。咱们一步步拆解解决:

问题根源分析

  1. 异步请求的时序差:Alamofire.request是后台异步操作,它不会阻塞主线程等待请求完成。你原来的代码里,setupUI()在getLowerJSON()调用后立刻执行,这时候网络请求还在跑,数据根本还没被解析赋值。
  2. 数据传递断层:你的getJSONS类拿到请求结果后,没有把lowereViewResponse对象传递给ViewController,所以控制器里的lowerData一直处于未初始化的状态。
  3. Model类的小疏漏:你的lowereViewResponse有重复的初始化方法实现,还漏了部分属性的JSON映射,这也可能导致数据解析异常。

解决方案

1. 改造网络请求类,添加回调闭包

先把getJSONS类(建议改成GetJSONS,符合Swift命名规范)的请求方法改成带闭包回调的形式,让它能把请求到的数据返回给调用者:

class GetJSONS {
    func getLowerJSON(completion: @escaping (lowereViewResponse?) -> Void) {
        let url = "http://tickerchart.com/interview/company-details.json"
        Alamofire.request(url).responseObject { (response: DataResponse<lowereViewResponse>) in
            // 请求完成后,把解析结果通过闭包传递出去
            completion(response.result.value)
        }
    }
}

2. 调整ViewController逻辑,等待数据返回后再更新UI

在控制器里,我们需要先发起请求,等拿到数据后再执行UI更新操作,还要确保UI操作在主线程执行:

class ViewController: UIViewController {
    // 声明存储数据的变量
    var lowerData: lowereViewResponse?

    override func viewDidLoad() {
        super.viewDidLoad()
        // 先请求数据,再更新UI
        fetchDataAndSetupUI()
    }

    private func fetchDataAndSetupUI() {
        GetJSONS().getLowerJSON { [weak self] response in
            guard let self = self, let fetchedData = response else {
                print("数据请求失败或解析出错")
                return
            }
            // 把拿到的数据赋值给lowerData
            self.lowerData = fetchedData
            // UI操作必须在主线程执行
            DispatchQueue.main.async {
                self.setupUI()
            }
        }
    }

    func setupUI(){
        // 用空合运算符处理可能为空的情况,避免崩溃
        print(lowerData?.companyName ?? "未获取到公司名称")
    }
}

3. 修复Model类的初始化和映射问题

把lowereViewResponse里重复的初始化方法合并,补全所有属性的JSON映射(建议类名改成LowereViewResponse):

class LowereViewResponse: NSObject, Mappable {
    var companyName: String?
    var symbol: String?
    var tradesCount: Int?
    var high: Int?
    var low: Int?
    var volume: Int?
    var amount: Int?
    var price: Int? // 原来代码里有这个变量,记得补充声明

    override init() {
        super.init()
    }

    required init?(map: Map) {
        super.init()
        // 设置默认值,避免空值问题
        companyName = ""
        symbol = ""
        tradesCount = 0
        high = 0
        low = 0
        volume = 0
        amount = 0
        price = 0
    }

    func mapping(map: Map) {
        companyName <- map["company-name"]
        symbol <- map["symbol"]
        tradesCount <- map["trades-count"]
        high <- map["high"]
        low <- map["low"]
        volume <- map["volume"]
        amount <- map["amount"] // 补全amount的映射
        price <- map["price"] // 补全price的映射
    }
}

为什么这样改?

  • 闭包回调让我们能在网络请求真正完成后拿到数据,彻底解决异步时序问题。
  • [weak self]的使用避免了循环引用,保证内存安全。
  • 强制在主线程更新UI,符合iOS的UI操作规则(所有UI操作必须在主线程执行)。
  • 修复Model类的疏漏,确保JSON能正确解析成我们需要的对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:01:36