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
相关产品推荐
相关产品推荐

