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

Swift中如何解析JSON里CustomerList数组的RegisterNumber等字段?

解析JSON中CustomerList数组字段的Swift实现方案

问题描述

我在应用中使用JSON API查询企业是否使用电子发票,返回的JSON数据示例如下:

{ 
  "ErrorStatus": null, 
  "Result": { 
    "CustomerList": [ 
      { 
        "RegisterNumber": "6320036072", 
        "Title": "VATAN BİLGİSAYAR SANAYİ VE TİCARET ANONİM ŞİRKETİ", 
        "Alias": "urn:mail:defaultpk@vatanbilgisayar.com", 
        "Type": "Özel", 
        "FirstCreationTime": "2014-01-01T05:35:20", 
        "AliasCreationTime": "2014-01-01T05:35:20" 
      } 
    ], 
    "ISEInvoiceCustomer": true 
  } 
}

我用Swift编写了getClientQuery函数来获取并解析数据,目前能正常拿到ISEInvoiceCustomer字段,但无法解析Result中CustomerList数组内的RegisterNumber、Title等字段,现有代码如下:

func getClientQuery(authorization:String) { 
    let url = NSURL(string: URLCustomerCheck+strRegisterNumber) 
    let request = NSMutableURLRequest(url: url! as URL) 
    request.httpMethod = "GET" 
    request.addValue(authorization, forHTTPHeaderField: "Authorization") 
    let task = URLSession.shared.dataTask(with: request as URLRequest) { data,response,error in 
        if error != nil { 
            let alert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.alert) 
            let okButton = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil) 
            alert.addAction(okButton) 
            self.present(alert, animated: true, completion: nil) 
        } else { 
            if data != nil { 
                do { 
                    let jSONResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String,AnyObject> 
                    DispatchQueue.main.async { 
                        print(jSONResult) 
                        let result = jSONResult["Result"] as! [String:AnyObject] 
                        //let customerList = result["CustomerList"] as! [[String:AnyObject]] 
                        let ISEInvoiceCustomer = String(describing: result["ISEInvoiceCustomer"]) 
                        self._lblISEinvoiceCustomer.text = " \(ISEInvoiceCustomer) " 
                    } 
                } catch { } 
            } 
        } 
    } 
    task.resume() 
}

解决方案

嘿,你其实已经把关键代码注释掉了!只需要恢复那一行并做一些安全优化,就能顺利解析CustomerList里的字段。另外,我建议尽量避免强制解包(!),用可选绑定来避免崩溃,下面是调整后的完整代码和说明:

修改后的解析代码

func getClientQuery(authorization: String) {
    // 先验证URL有效性,避免强制解包崩溃
    guard let url = URL(string: URLCustomerCheck + strRegisterNumber) else {
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "Error", message: "Invalid URL", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .cancel))
            self.present(alert, animated: true)
        }
        return
    }
    
    var request = URLRequest(url: url) // 使用Swift原生的URLRequest替代NSMutableURLRequest
    request.httpMethod = "GET"
    request.addValue(authorization, forHTTPHeaderField: "Authorization")
    
    let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
        guard let self = self else { return }
        
        // 处理网络错误
        if let error = error {
            DispatchQueue.main.async {
                let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .cancel))
                self.present(alert, animated: true)
            }
            return
        }
        
        // 确保数据存在
        guard let data = data else {
            DispatchQueue.main.async {
                let alert = UIAlertController(title: "Error", message: "No data received", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .cancel))
                self.present(alert, animated: true)
            }
            return
        }
        
        do {
            // 安全解析JSON层级
            guard let jsonResult = try JSONSerialization.jsonObject(with: data) as? [String: Any],
                  let result = jsonResult["Result"] as? [String: Any],
                  let customerList = result["CustomerList"] as? [[String: Any]] else {
                DispatchQueue.main.async {
                    let alert = UIAlertController(title: "Error", message: "Failed to parse JSON structure", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .cancel))
                    self.present(alert, animated: true)
                }
                return
            }
            
            // 正确解析ISEInvoiceCustomer为Bool类型(比转字符串更准确)
            let isEInvoiceCustomer = result["ISEInvoiceCustomer"] as? Bool ?? false
            
            DispatchQueue.main.async {
                self._lblISEinvoiceCustomer.text = "\(isEInvoiceCustomer)"
                
                // 遍历CustomerList数组,解析每个客户的字段
                for customer in customerList {
                    // 用可选绑定+默认值处理字段缺失情况
                    let registerNumber = customer["RegisterNumber"] as? String ?? "N/A"
                    let title = customer["Title"] as? String ?? "N/A"
                    let alias = customer["Alias"] as? String ?? "N/A"
                    let type = customer["Type"] as? String ?? "N/A"
                    let firstCreationTime = customer["FirstCreationTime"] as? String ?? "N/A"
                    let aliasCreationTime = customer["AliasCreationTime"] as? String ?? "N/A"
                    
                    // 这里可以把解析出的字段展示到UI或存入模型
                    print("Register Number: \(registerNumber)")
                    print("Company Title: \(title)")
                    // ... 其他字段的业务逻辑
                }
            }
        } catch let parseError {
            DispatchQueue.main.async {
                let alert = UIAlertController(title: "Error", message: "JSON Parse Error: \(parseError.localizedDescription)", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .cancel))
                self.present(alert, animated: true)
            }
        }
    }
    task.resume()
}

关键解析要点

  • 恢复并优化CustomerList解析:通过guard let customerList = result["CustomerList"] as? [[String: Any]]安全获取数组,避免强制解包导致崩溃。
  • 遍历数组提取字段:CustomerList是数组结构,所以用for-in循环逐个解析每个客户对象的字段,同时给每个字段设置默认值(如"N/A"),防止字段缺失时出现nil。
  • 类型转换优化:把ISEInvoiceCustomer直接转成Bool类型,而不是用String(describing:),这样UI上会显示更准确的true/false,而不是"Optional(true)"。
  • 异常情况处理:新增了URL验证、空数据处理、解析失败处理等逻辑,让代码更健壮。

进阶方案:使用Codable简化解析

如果你的JSON结构固定,推荐使用Swift的Codable协议,代码会更简洁易维护。先定义对应的模型:

// 对应整个API响应
struct APIResponse: Codable {
    let errorStatus: String?
    let result: ResultData
    
    // 映射JSON的蛇形命名到Swift的驼峰命名
    enum CodingKeys: String, CodingKey {
        case errorStatus = "ErrorStatus"
        case result = "Result"
    }
}

// 对应Result节点
struct ResultData: Codable {
    let customerList: [Customer]
    let isEInvoiceCustomer: Bool
    
    enum CodingKeys: String, CodingKey {
        case customerList = "CustomerList"
        case isEInvoiceCustomer = "ISEInvoiceCustomer"
    }
}

// 对应CustomerList里的单个客户
struct Customer: Codable {
    let registerNumber: String
    let title: String
    let alias: String
    let type: String
    let firstCreationTime: String
    let aliasCreationTime: String
    
    enum CodingKeys: String, CodingKey {
        case registerNumber = "RegisterNumber"
        case title = "Title"
        case alias = "Alias"
        case type = "Type"
        case firstCreationTime = "FirstCreationTime"
        case aliasCreationTime = "AliasCreationTime"
    }
}

然后解析代码可以简化成:

do {
    let apiResponse = try JSONDecoder().decode(APIResponse.self, from: data)
    DispatchQueue.main.async {
        self._lblISEinvoiceCustomer.text = "\(apiResponse.result.isEInvoiceCustomer)"
        // 遍历客户列表
        for customer in apiResponse.result.customerList {
            print("Register Number: \(customer.registerNumber)")
            print("Company Title: \(customer.title)")
            // ... 其他字段的使用
        }
    }
} catch let parseError {
    DispatchQueue.main.async {
        let alert = UIAlertController(title: "Error", message: "JSON Parse Error: \(parseError.localizedDescription)", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .cancel))
        self.present(alert, animated: true)
    }
}

这种方式不需要手动处理每个字段的类型转换,编译器会帮你检查类型匹配,大大降低出错概率。


内容的提问来源于stack exchange,提问作者C. Sayin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:09:29