SwiftUI中JSONDecoder解码始终返回nil问题求助
SwiftUI Mock JSON解码返回nil的问题
我开发了一个SwiftUI应用,为测试需求创建了Mock仓库,从本地JSON文件获取数据而非调用API,但JSONDecoder的解码结果始终为nil。
本地JSON内容(存储于项目根目录):
[ { "ts": 1000000, "id": 1, "userName": "honeybee", "userLocation": "Honey bee", "userImageUrl": "user_1", "title": "Here", "postType": "post", "postImageUrl": "food_1", }, { "ts": 1000000, "id": 2, "userName": "honeybee", "userLocation": "Honey bee", "userImageUrl": "user_2", "title": "Here", "postType": "store", "postImageUrl": "food_2" }, ]
FeedItemEntity模型代码:
enum PostType: String, Codable { case Post = "post" case Store = "store" case Restaurant = "restaurant" case Review = "review" case Recipe = "recipe" } struct FeedItemEntity: Codable { var ts: Int var userName: String var userLocation: String var userImageUrl: String var title: String var postImageUrl: String var postType: PostType var rating: Int } extension FeedItemEntity: Identifiable { var id: UUID { let id = UUID() return id } }
Mock服务代码:
class MockedFeedService: FeedServiceProtocol { static let shared = MockedFeedService() func getFeed() -> Future<[ios_foodloose_app.FeedItemEntity], Error> { return Future<[FeedItemEntity], Error> { promise in guard let url = Bundle(for: MockedFeedService.self).url(forResource: "basic-test-feed-response",withExtension: "json"), let data = try? Data(contentsOf: url) else { return promise(.failure(NSError(domain: "", code: 401, userInfo: [ NSLocalizedDescriptionKey: "Error"]))) } let response = try? JSONDecoder().decode( [FeedItemEntity].self, from: data) promise(.success(response!)) } } }
解码失败的原因及修正方案
JSON语法错误
第一个JSON对象的"postImageUrl": "food_1",末尾多了逗号,数组最后也存在多余逗号。JSON不允许尾逗号(trailing comma),这会直接导致解析失败。模型字段不匹配
FeedItemEntity里的rating是必填Int类型,但JSON中完全没有这个字段。解码时找不到对应值会抛出错误,try?会将错误转为nil。Identifiable扩展冗余
你手动生成UUID作为id,但JSON本身包含id字段,模型却未声明该属性,既浪费资源也不符合数据对应逻辑。错误处理缺失
用try?直接忽略了解码错误,无法获取具体失败原因,导致无法快速定位问题。
修正后的代码示例
修正后的JSON
[ { "ts": 1000000, "id": 1, "userName": "honeybee", "userLocation": "Honey bee", "userImageUrl": "user_1", "title": "Here", "postType": "post", "postImageUrl": "food_1" }, { "ts": 1000000, "id": 2, "userName": "honeybee", "userLocation": "Honey bee", "userImageUrl": "user_2", "title": "Here", "postType": "store", "postImageUrl": "food_2" } ]
修正后的FeedItemEntity
enum PostType: String, Codable { case post = "post" case store = "store" case restaurant = "restaurant" case review = "review" case recipe = "recipe" } struct FeedItemEntity: Codable, Identifiable { let id: Int // 直接使用JSON中的id var ts: Int var userName: String var userLocation: String var userImageUrl: String var title: String var postImageUrl: String var postType: PostType var rating: Int? // 改为可选类型,适配JSON无该字段的情况 }
修正后的Mock服务(添加错误处理)
class MockedFeedService: FeedServiceProtocol { static let shared = MockedFeedService() func getFeed() -> Future<[FeedItemEntity], Error> { return Future<[FeedItemEntity], Error> { promise in guard let url = Bundle(for: MockedFeedService.self).url(forResource: "basic-test-feed-response",withExtension: "json"), let data = try? Data(contentsOf: url) else { return promise(.failure(NSError(domain: "MockService", code: 401, userInfo: [NSLocalizedDescriptionKey: "无法加载JSON文件"]))) } do { let response = try JSONDecoder().decode([FeedItemEntity].self, from: data) promise(.success(response)) } catch { print("解码错误:\(error)") // 打印错误便于调试 promise(.failure(error)) } } } }
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

