SwiftUI JSON解码器抛出空数据异常:iPhone XS调试问题求助
SwiftUI调试异常:iPhone XS反复出现JSON空数据解码失败,iPhone 8正常
问题情况
在XCode中学习SwiftUI时碰到特殊问题:两台iOS版本、开发配置完全一致的iPhone,调试时仅iPhone XS会出现JSON解码器抛出空数据的异常,临时修改代码重建项目能暂时解决,但次日问题必然复发;iPhone 8全程无此问题。
涉事代码
func loadJSON<T: Decodable>(_ filename: String) -> T { let data: Data guard let file = URL(string: filename) else { fatalError("Couldn't find \(filename).") } do { data = try Data(contentsOf: file) } catch { //fatalError("Couldn't load \(filename):\n\(error)") data = Data.init() // 如果删掉这行,异常会从上面的try行抛出 } do { let decoder = JSONDecoder() return try decoder.decode(T.self, from: data) } catch { fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)") // <- 错误触发位置 } }
调试输出
Thread 2: Fatal error: Couldn't parse http://**myURL** as Array<ItemClass>: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Unable to parse empty data." UserInfo={NSDebugDescription=Unable to parse empty data.})))
排查与解决建议
- 替换同步网络请求:
Data(contentsOf:)是同步网络请求,无超时控制、缓存管理,不同设备的网络栈处理逻辑存在差异,这是核心问题。换成URLSession异步请求,示例如下:func loadJSON<T: Decodable>(_ urlString: String, completion: @escaping (Result<T, Error>) -> Void) { guard let url = URL(string: urlString) else { completion(.failure(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效URL"]))) return } URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(error)) return } guard let data = data else { completion(.failure(NSError(domain: "", code: -2, userInfo: [NSLocalizedDescriptionKey: "空数据"]))) return } do { let decoded = try JSONDecoder().decode(T.self, from: data) completion(.success(decoded)) } catch { completion(.failure(error)) } }.resume() } - 移除空Data兜底逻辑:请求失败时直接返回错误,不要给空Data让解码器报错,便于定位真实问题
- 清理项目缓存:删除XCode的Derived Data(路径:XCode→Preferences→Locations→Derived Data,点击右侧箭头打开文件夹删除),执行Clean后彻底重建项目
- 重置设备网络:iPhone XS可能存在网络缓存异常,尝试重启设备或重置网络设置(设置→通用→传输或还原iPhone→重置→重置网络设置)
- 检查URL合法性:确认传入的URL字符串无编码错误,若为本地文件,改用
Bundle.main.url(forResource:withExtension:)构造本地文件URL
内容的提问来源于stack exchange,提问作者SwiftRookie1704
相关产品推荐
相关产品推荐

