在swift iOS中使用JSON解码器解析本地Json
Posted
技术标签:
【中文标题】在swift iOS中使用JSON解码器解析本地Json【英文标题】:Local Json parsing with JSON Decoder in swift iOS 【发布时间】:2021-12-22 15:45:27 【问题描述】:我想解析本地 JSON 并使用 JSON 解码器访问内部内容。我是 JSON 解码器的新手,任何人都可以建议。
JSON:
[
"bookmark_intro":
"title": "What's new in bookmarks",
"enabled": "yes",
"content": [
"subtitle": "Organize with folders",
"content": "Organize your bookmarks in folders for quick and easy access.",
"icon": "image1.png"
,
"subtitle": "Share and subscribe",
"content": "Share your folders with your colleagues and subscribe to their folders to keep you informed about updates.",
"icon": "image2.png"
,
"subtitle": "And lots more!",
"content": "Edit bookmarks easier, add bookmarks to multiple folders - all that even offline and synced across all your apps and devices.",
"icon": "image3.png"
]
]
创建模型如下:
struct PremiumTutorialModel : Codable
let bookmark_intro : Bookmark_intro?
enum CodingKeys: String, CodingKey
case bookmark_intro = "bookmark_intro"
init(from decoder: Decoder) throws
let values = try decoder.container(keyedBy: CodingKeys.self)
bookmark_intro = try values.decodeIfPresent(Bookmark_intro.self, forKey: .bookmark_intro)
struct Bookmark_intro : Codable
let title : String?
let enabled : String?
let content : [Content]?
enum CodingKeys: String, CodingKey
case title = "title"
case enabled = "enabled"
case content = "content"
init(from decoder: Decoder) throws
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try values.decodeIfPresent(String.self, forKey: .title)
enabled = try values.decodeIfPresent(String.self, forKey: .enabled)
content = try values.decodeIfPresent([Content].self, forKey: .content)
struct Content : Codable
let subtitle : String?
let content : String?
let icon : String?
enum CodingKeys: String, CodingKey
case subtitle = "subtitle"
case content = "content"
case icon = "icon"
init(from decoder: Decoder) throws
let values = try decoder.container(keyedBy: CodingKeys.self)
subtitle = try values.decodeIfPresent(String.self, forKey: .subtitle)
content = try values.decodeIfPresent(String.self, forKey: .content)
icon = try values.decodeIfPresent(String.self, forKey: .icon)
我试图使用这个函数解析和访问数据,它没有返回模型上的完整数据,任何人都可以提出正确的方法。
func loadJson(fileName: String) -> PremiumTutorialModel?
let decoder = JSONDecoder()
guard
let url = Bundle.main.url(forResource: fileName, withExtension: "json"),
let data = try? Data(contentsOf: url),
let model = try? decoder.decode(PremiumTutorialModel.self, from: data)
else
return nil
return model
谁能建议使用 JSON 解码器解析 json 的正确方法。
【问题讨论】:
对于初学者来说,你的 json 中最外层的类型是一个数组,所以它应该是decoder.decode([PremiumTutorialModel].self...
,你不应该为你自己的本地 json 自定义任何 init(from:)
,改为更改 json 文件并仅在需要时使您的属性可选。此外,在开发和测试时,您应该在解码时使用适当的错误处理。错误消息通常很有帮助。
【参考方案1】:
您可以创建这些模型:
import Foundation
// MARK: - PremiumTutorialModelElement
struct PremiumTutorialModelElement: Codable
let bookmarkIntro: BookmarkIntro
enum CodingKeys: String, CodingKey
case bookmarkIntro = "bookmark_intro"
// MARK: - BookmarkIntro
struct BookmarkIntro: Codable
let title: String
let enabled: String
let content: [Content]
enum CodingKeys: String, CodingKey
case title = "title"
case enabled = "enabled"
case content = "content"
// MARK: - Content
struct Content: Codable
let subtitle: String
let content: String
let icon: String
enum CodingKeys: String, CodingKey
case subtitle = "subtitle"
case content = "content"
case icon = "icon"
typealias PremiumTutorialModel = [PremiumTutorialModelElement]
这个website 非常适合生成 JSON -> Swift 模型。
编辑:
正如@Sulthan 指出的那样,在这种情况下,CodingKeys 是多余的。为了清楚起见,我将它们包括在内,以便其他人更容易修改,但这也可以:
import Foundation
// MARK: - PremiumTutorialModelElement
struct PremiumTutorialModelElement: Codable
let bookmarkIntro: BookmarkIntro
enum CodingKeys: String, CodingKey
case bookmarkIntro = "bookmark_intro"
// MARK: - BookmarkIntro
struct BookmarkIntro: Codable
let title, enabled: String
let content: [Content]
// MARK: - Content
struct Content: Codable
let subtitle, content, icon: String
typealias PremiumTutorialModel = [PremiumTutorialModelElement]
【讨论】:
CodingKeys
在这种情况下不是必需的。
@Sulthan True。在这种情况下,它们对于结构是多余的。为了清晰起见,我更喜欢添加它们,这样其他人可以更轻松地根据自己的需要调整代码。
至少,您可以删除分配并仅将其保留为case subtitle
而不是case subtitle = "subtitle"
@Sulthan 再次,真的。再一次,我认为其他人在看到这一点时更容易根据自己的需要进行修改。如果 JSON 中的名称是 "subtitle"
,但您想调用属性 description
,该怎么办?那么很高兴有这个作为模板。
其实,没有。添加不必要的代码意味着 1/ 更难阅读代码 2/ 增加错误的机会。 3/ 编写最初不需要的代码的必要时间。需要时添加代码。【参考方案2】:
我创建了一个可以访问 json 的方法,如下所示。
func loadJson(fileName: String) -> PremiumTutorialModel?
let decoder = JSONDecoder()
guard
let url = Bundle.main.url(forResource: fileName, withExtension: "json"),
let data = try? Data(contentsOf: url),
let model = try? decoder.decode([PremiumTutorialModel].self, from: data)
else
return nil
return model[0]
【讨论】:
以上是关于在swift iOS中使用JSON解码器解析本地Json的主要内容,如果未能解决你的问题,请参考以下文章
我如何使用解码器在swift 4中解析tableview中的json数组
在 Swift 中使用 JSON 解码器难以解析 JSON 中的整数值
如何在 swift iOS 中使用 swift 高阶函数从本地 json 创建 ViewModel