如何在Swift/iOS中导入解析Pandas导出的JSON文件?
解决Swift/iOS解析Pandas导出的JSON Lines文件问题
看起来你遇到的问题大概率是JSON格式不匹配导致的——你用Pandas的lines=True导出的是**JSON Lines(每行一个独立JSON对象)**格式,但Swift的Codable默认期望的是标准JSON数组(外层用[]包裹,对象间用逗号分隔),直接用SwiftyJSON解析整个文件也会因为格式不合法报错。
先确认下你的sample.json内容大概是这种结构:
{"url":"xxx", "name":"xxx", ...} {"url":"yyy", "name":"yyy", ...}
而非标准的数组格式:
[{"url":"xxx", ...}, {"url":"yyy", ...}]
下面给你两种可行的解决思路:
方案一:修改Pandas导出格式(最简单直接)
如果可以调整导出代码,去掉lines=True参数,让Pandas直接导出标准JSON数组:
shops.to_json("sample.json", orient='records', force_ascii=False)
这样导出的文件就是合法的JSON结构,Swift里直接用Codable解析数组即可:
struct Restaurant: Codable { let url: String let name: String let address: String let pref: String let zip: String let tel: String let latitude: Float let longitude: Float let price: String // 补充你的其他属性... } // 解析示例代码 if let url = Bundle.main.url(forResource: "sample", withExtension: "json"), let data = try? Data(contentsOf: url), let restaurants = try? JSONDecoder().decode([Restaurant].self, from: data) { print("成功解析 \(restaurants.count) 条餐厅数据") }
方案二:在Swift中适配JSON Lines格式
如果没办法修改导出的JSON文件,那就需要手动读取文件的每一行,逐个解析JSON对象:
// 读取文件内容并按行分割 guard let url = Bundle.main.url(forResource: "sample", withExtension: "json"), let content = try? String(contentsOf: url) else { print("无法读取JSON文件") return } // 过滤空行,避免解析出错 let lines = content.components(separatedBy: .newlines).filter { !$0.isEmpty } let decoder = JSONDecoder() var restaurants = [Restaurant]() for line in lines { guard let data = line.data(using: .utf8) else { print("行内容转Data失败: \(line)") continue } do { let restaurant = try decoder.decode(Restaurant.self, from: data) restaurants.append(restaurant) } catch { print("解析行失败: \(error.localizedDescription),行内容: \(line)") } } print("最终解析得到 \(restaurants.count) 条数据")
如果用SwiftyJSON处理,逻辑也是类似的逐行解析:
import SwiftyJSON guard let url = Bundle.main.url(forResource: "sample", withExtension: "json"), let content = try? String(contentsOf: url) else { return } let lines = content.components(separatedBy: .newlines).filter { !$0.isEmpty } var restaurants = [Restaurant]() for line in lines { guard let data = line.data(using: .utf8), let json = try? JSON(data: data) else { continue } // 手动映射到Restaurant对象 let restaurant = Restaurant( url: json["url"].stringValue, name: json["name"].stringValue, address: json["address"].stringValue, pref: json["pref"].stringValue, zip: json["zip"].stringValue, tel: json["tel"].stringValue, latitude: json["latitude"].floatValue, longitude: json["longitude"].floatValue, price: json["price"].stringValue // 补充其他属性... ) restaurants.append(restaurant) }
最后提醒几个细节:
- 确认Pandas导出的
latitude和longitude是数值类型,而非字符串,否则Swift用Float解析会失败 - 如果有可选字段,记得在
Restaurant结构体中把对应属性设为可选类型(比如let price: String?) - 解析时保留错误捕获逻辑,能帮你快速定位具体哪一行或哪个字段出了问题
内容的提问来源于stack exchange,提问作者YOSUKE




