如何从主视图调用Mappable类变量?返回值为空问题
解决异步网络请求后数据为空的问题
嘿,我看你遇到的是个很典型的异步请求时序问题,再加上数据传递环节的缺失,导致调用lowerData.companyName时拿到空值。咱们一步步拆解解决:
问题根源分析
- 异步请求的时序差:
Alamofire.request是后台异步操作,它不会阻塞主线程等待请求完成。你原来的代码里,setupUI()在getLowerJSON()调用后立刻执行,这时候网络请求还在跑,数据根本还没被解析赋值。 - 数据传递断层:你的
getJSONS类拿到请求结果后,没有把lowereViewResponse对象传递给ViewController,所以控制器里的lowerData一直处于未初始化的状态。 - 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
相关产品推荐
相关产品推荐

