如何将 List 类型与 Codable 一起使用? (领域斯威夫特)
How to use List type with Codable? (RealmSwift)
问题是List类型不符合Codable,以下class无法插入到Realm中。
例如,
class Book: Codable {
var name: String = ""
var author: String = ""
var tags = [String]()
}
考虑到上面的class符合Codable,如果把这个class存到Realm中,需要使用List<Object>
类型而不是[String]
class Book: Object, Codable {
@objc dynamic var name: String = ""
@objc dynamic var author: String = ""
var tags = List<Tag>()
required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
author = try container.decode(String.self, forKey: .author)
tags = try container.decode(List<Tag>.self, forKey: .tags) // this is problem.
}
}
class Tag: Object, Codable {
@objc dynamic var string: String = ""
required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
string = try container.decode(String.self, forKey: .string)
}
}
为了符合 Codable,应该实现 Decodable
协议。 (required convenience init(from decoder: Decoder) throws
)
但是,List
类型不符合Codable
(Decodable
),如果class有List
类型,则无法使用Codable .
如何解决这个问题?
谢谢,
你快到了。在初始化程序中,您可以使用解码后的数组初始化列表。基本上,改变
tags = try container.decode(List<Tag>.self, forKey: .tags) // this is problem.
到
let tagsArray = try container.decode([Tag].self, forKey: .tags)
tags = List(tagsArray) // Now you are good
正如评论中指出的那样,List
构造函数不再像这样工作
你现在想要:
tags.append(objectsIn: tagsArray)
接受的答案只有一个问题。 Realm 指定列表应该是 let
(Constants) 因此,要修改解决方案以遵循最佳实践,您只需将列表设为 let
,然后循环将结果附加到数组。
// Change this Line in [Your Code]
// to a let (Constant)
var tags = List<Tag>()
到 let tags = List<Tag>()
然后改变
tags = try container.decode(List<Tag>.self, forKey: .tags)
到
let tagsArray = try container.decode([Tag].self, forKey: .tags)
tagsArray.forEach{ tags.append([=12=]) }
这就是您创建领域的方式/Swift 4 个可编码模型。
有关 JSON 响应、模型和 URLSession 的更多详细信息:Read this article
import RealmSwift
class VendorsList : Object, Decodable {
@objc dynamic var id : Int = 0
@objc dynamic var name : String?
@objc dynamic var logo : String?
// Create your Realm List.
var kitchensList = List<VendorKitchens>()
override class func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case name
case logo
// Set JSON Object Key
case kitchensList = "kitchens"
}
public required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.logo = try container.decode(String.self, forKey: .logo)
// Map your JSON Array response
let kitchens = try container.decodeIfPresent([VendorKitchens].self, forKey: .kitchensList) ?? [VendorKitchens()]
kitchensList.append(objectsIn: kitchens)
}
}
class VendorKitchens : Object, Decodable {
@objc dynamic var id : Int = 0
@objc dynamic var name : String?
override class func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case name
}
}
我们可以使用扩展来使 List 符合 Codable:
extension List : Decodable where Element : Decodable {
public convenience init(from decoder: Decoder) throws {
self.init()
var container = try decoder.unkeyedContainer()
while !container.isAtEnd {
let element = try container.decode(Element.self)
self.append(element)
}
} }
extension List : Encodable where Element : Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
for element in self {
try element.encode(to: container.superEncoder())
}
} }
如果其他人需要,我还得到了 RealmOptional 的扩展。
https://gist.github.com/ansonyao/41137bb3cbbca8ef31a13b6bc96ee422
问题是List类型不符合Codable,以下class无法插入到Realm中。
例如,
class Book: Codable {
var name: String = ""
var author: String = ""
var tags = [String]()
}
考虑到上面的class符合Codable,如果把这个class存到Realm中,需要使用List<Object>
类型而不是[String]
class Book: Object, Codable {
@objc dynamic var name: String = ""
@objc dynamic var author: String = ""
var tags = List<Tag>()
required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
author = try container.decode(String.self, forKey: .author)
tags = try container.decode(List<Tag>.self, forKey: .tags) // this is problem.
}
}
class Tag: Object, Codable {
@objc dynamic var string: String = ""
required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
string = try container.decode(String.self, forKey: .string)
}
}
为了符合 Codable,应该实现 Decodable
协议。 (required convenience init(from decoder: Decoder) throws
)
但是,List
类型不符合Codable
(Decodable
),如果class有List
类型,则无法使用Codable .
如何解决这个问题?
谢谢,
你快到了。在初始化程序中,您可以使用解码后的数组初始化列表。基本上,改变
tags = try container.decode(List<Tag>.self, forKey: .tags) // this is problem.
到
let tagsArray = try container.decode([Tag].self, forKey: .tags)
tags = List(tagsArray) // Now you are good
正如评论中指出的那样,List
构造函数不再像这样工作
你现在想要:
tags.append(objectsIn: tagsArray)
接受的答案只有一个问题。 Realm 指定列表应该是 let
(Constants) 因此,要修改解决方案以遵循最佳实践,您只需将列表设为 let
,然后循环将结果附加到数组。
// Change this Line in [Your Code]
// to a let (Constant)
var tags = List<Tag>()
到 let tags = List<Tag>()
然后改变
tags = try container.decode(List<Tag>.self, forKey: .tags)
到
let tagsArray = try container.decode([Tag].self, forKey: .tags)
tagsArray.forEach{ tags.append([=12=]) }
这就是您创建领域的方式/Swift 4 个可编码模型。
有关 JSON 响应、模型和 URLSession 的更多详细信息:Read this article
import RealmSwift
class VendorsList : Object, Decodable {
@objc dynamic var id : Int = 0
@objc dynamic var name : String?
@objc dynamic var logo : String?
// Create your Realm List.
var kitchensList = List<VendorKitchens>()
override class func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case name
case logo
// Set JSON Object Key
case kitchensList = "kitchens"
}
public required convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.logo = try container.decode(String.self, forKey: .logo)
// Map your JSON Array response
let kitchens = try container.decodeIfPresent([VendorKitchens].self, forKey: .kitchensList) ?? [VendorKitchens()]
kitchensList.append(objectsIn: kitchens)
}
}
class VendorKitchens : Object, Decodable {
@objc dynamic var id : Int = 0
@objc dynamic var name : String?
override class func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case name
}
}
我们可以使用扩展来使 List 符合 Codable:
extension List : Decodable where Element : Decodable {
public convenience init(from decoder: Decoder) throws {
self.init()
var container = try decoder.unkeyedContainer()
while !container.isAtEnd {
let element = try container.decode(Element.self)
self.append(element)
}
} }
extension List : Encodable where Element : Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
for element in self {
try element.encode(to: container.superEncoder())
}
} }
如果其他人需要,我还得到了 RealmOptional 的扩展。
https://gist.github.com/ansonyao/41137bb3cbbca8ef31a13b6bc96ee422