我试图从API端点返回的数据中呈现视图.我的
JSON看起来(大致)像这样:
{ "sections": [ { "title": "Featured","section_layout_type": "featured_panels","section_items": [ { "item_type": "foo","id": 3,"title": "Bisbee1","audio_url": "http://example.com/foo1.mp3","feature_image_url" : "http://example.com/feature1.jpg" },{ "item_type": "bar","id": 4,"title": "Mortar8","video_url": "http://example.com/video.mp4","director" : "John Smith","feature_image_url" : "http://example.com/feature2.jpg" } ] } ] }
我有一个对象,表示如何在我的UI中布局视图.它看起来像这样:
public struct ViewLayoutSection : Codable { var title: String = "" var sectionLayoutType: String var sectionItems: [ViewLayoutSectionItemable] = [] }
ViewLayoutSectionItemable是一种协议,其中包括标题和要在布局中使用的图像的URL等.
但是,sectionItems数组实际上由不同类型组成.我想要做的是将每个section项实例化为它自己的类的一个实例.
如何为ViewLayoutSection设置init(来自解码器:解码器)方法,让我迭代该JSON数组中的项并在每种情况下创建正确类的实例?
解决方法
我建议你明智地使用Codable.如果您只想从JSON解码类型而不对其进行编码,那么仅将其与Decodable相符就足够了.既然你已经发现你需要手动解码它(通过自定义的init实现(来自解码器:解码器)),那么问题就变成了:最不痛苦的方法是什么?
一,数据模型.请注意,ViewLayoutSectionItemable及其采用者不符合Decodable:
enum ItemType: String,Decodable { case foo case bar } protocol ViewLayoutSectionItemable { var id: Int { get } var itemType: ItemType { get } var title: String { get set } var imageURL: URL { get set } } struct Foo: ViewLayoutSectionItemable { let id: Int let itemType: ItemType var title: String var imageURL: URL // Custom properties of Foo var audioURL: URL } struct Bar: ViewLayoutSectionItemable { let id: Int let itemType: ItemType var title: String var imageURL: URL // Custom properties of Bar var videoURL: URL var director: String }
接下来,我们将如何解码JSON:
struct Sections: Decodable { var sections: [ViewLayoutSection] } struct ViewLayoutSection: Decodable { var title: String = "" var sectionLayoutType: String var sectionItems: [ViewLayoutSectionItemable] = [] // This struct use snake_case to match the JSON so we don't have to provide a custom // CodingKeys enum. And since it's private,outside code will never see it private struct GenericItem: Decodable { let id: Int let item_type: ItemType var title: String var feature_image_url: URL // Custom properties of all possible types. Note that they are all optionals var audio_url: URL? var video_url: URL? var director: String? } private enum CodingKeys: String,CodingKey { case title case sectionLayoutType = "section_layout_type" case sectionItems = "section_items" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) title = try container.decode(String.self,forKey: .title) sectionLayoutType = try container.decode(String.self,forKey: .sectionLayoutType) sectionItems = try container.decode([GenericItem].self,forKey: .sectionItems).map { item in switch item.item_type { case .foo: // It's OK to force unwrap here because we already // kNow what type the item object is return Foo(id: item.id,itemType: item.item_type,title: item.title,imageURL: item.feature_image_url,audioURL: item.audio_url!) case .bar: return Bar(id: item.id,videoURL: item.video_url!,director: item.director!) } } }
用法:
let sections = try JSONDecoder().decode(Sections.self,from: json).sections
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。