How to use list type with Codable? (RealmSwift)
Problem: List type does not match Codable, below class cannot be inserted into Realm.
eg,
class Book: Codable {
var name: String = ""
var author: String = ""
var tags = [String]()
}
Consider the above class corresponding to Codable, if you save this class in Realm, it needs to use type List<Object>
instead[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)
}
}
To be compliant with Codable, it must implement the protocol Decodable
. ( required convenience init(from decoder: Decoder) throws
)
But the type List
does not match Codable
( Decodable
), it is not possible to use Codable if the class has a type List
.
How to solve this problem?
Thank,
source to share
You're almost there. Inside the initializer, you can initialize the list using the decoded array. Basically, change
tags = try container.decode(List<Tag>.self, forKey: .tags) // this is problem.
to
let tagsArray = try container.decode([Tag].self, forKey: .tags)
tags = List(tagsArray) // Now you are good
source to share
There is only one problem with the accepted answer. Realm indicates that lists should be let
(Constants). To change your mind to follow the guidelines, you just have to make your list a let
and then loop over adding the results to your array.
// Change this Line in [Your Code]
// to a let (Constant)
var tags = List<Tag>()
to let tags = List<Tag>()
Then change
tags = try container.decode(List<Tag>.self, forKey: .tags)
to
let tagsArray = try container.decode([Tag].self, forKey: .tags)
tagsArray.forEach{ tags.append($0) }
source to share
This is how you create your Realm / Swift 4 Codable models.
More about JSON Response, Model and 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
}
}
source to share