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,

+3


source to share


3 answers


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

      

+5


source


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) }

      

+2


source


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
    }
}

      

+1


source







All Articles