Issue with Model class of Realm

Viewed 50

I was going through some model classes of a project(Realm is being used). This is one class…

@objcMembers class CommA: Object {
  dynamic var id = 0
  dynamic var recipientId = "0"
  dynamic var name: String?
  dynamic var picture: String?
  dynamic var unreadMessageCount = 0
  dynamic var lastMessage: MyMessage?

  override class func primaryKey() -> String? {
    return "id"
  }
}

This pretty much seems easy. A class with variables and a primary key defined.. But there is another class which looks like so…

@objcMembers class CommB: Object, Codable {
  dynamic var id = "0"
  dynamic var name: String?
  dynamic var picture: String?
  dynamic var status: String?
  dynamic var lastSeen: String?
  dynamic var unreadMessageCount = 0
  dynamic var lastMessage: MyMessage?

  enum CodingKeys: String, CodingKey {
    case id = "UsrID"
    case name = "UserName"
    case picture = "UsrPicture"
    case status = "ChatStatus"
  }

  required init() {
    super.init()
  }

  required init(value: Any, schema: RLMSchema) {
    super.init(value: value, schema: schema)
  }

  required init(realm: RLMRealm, schema: RLMObjectSchema) {
    super.init(realm: realm, schema: schema)
  }

  convenience init(id: String, name: String, picture: String, status: String) {
    self.init()
    self.id = id
    self.name = name
    self.picture = picture
    self.status = status
  }

  convenience required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let id = try container.decode(String.self, forKey: .id)
    let name = try container.decode(String.self, forKey: .name)
    let picture = try container.decode(String.self, forKey: .picture)
    //let status = try container.decode(String.self, forKey: .status)
    self.init(id: id, name: name, picture: picture, status: "status")
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(id, forKey: .id)
    try container.encode(name, forKey: .name)
    try container.encode(picture, forKey: .picture)
    try container.encode(status, forKey: .status)
  }

  override class func primaryKey() -> String? {
    return "id"
  }
}

What I don’t understand here is why the enum, required init, convenience required init etc. is used…?

1 Answers

In fact, some of the initialisers are redundant. Your code can be shortened to

@objcMembers class CommB: Object, Codable {
    dynamic var id = "0"
    dynamic var name: String?
    dynamic var picture: String?
    dynamic var status: String?
    dynamic var lastSeen: String?
    dynamic var unreadMessageCount = 0
    dynamic var lastMessage: MyMessage?

    enum CodingKeys: String, CodingKey {
        case id = "UsrID"
        case name = "UserName"
        case picture = "UsrPicture"
        case status = "ChatStatus"
    }

    convenience init(id: String, name: String, picture: String, status: String) {
        self.init()
        self.id = id
        self.name = name
        self.picture = picture
        self.status = status
    }

    convenience required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let id = try container.decode(String.self, forKey: .id)
        let name = try container.decode(String.self, forKey: .name)
        let picture = try container.decode(String.self, forKey: .picture)
        //let status = try container.decode(String.self, forKey: .status)
        self.init(id: id, name: name, picture: picture, status: "status")
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(picture, forKey: .picture)
        try container.encode(status, forKey: .status)
    }

    override class func primaryKey() -> String? {
        return "id"
    }
}

I have removed

  required init() {
    super.init()
  }

  required init(value: Any, schema: RLMSchema) {
    super.init(value: value, schema: schema)
  }

  required init(realm: RLMRealm, schema: RLMObjectSchema) {
    super.init(realm: realm, schema: schema)
  }

Everything else is quite important.

CommB is not only a realm object, but also Codable. And the author of it wanted to customise the de/encoding behaviour so that the de/encoder only de/encodes id, name, picture and status. To do this, a CodingKey enum needs to be created, storing the coding keys. Also, convenience required init(from decoder: Decoder) and func encode(to encoder: Encoder) needs to be implemented.

The convenience init(id: String, name: String, picture: String, status: String) initialiser is there because the init(from decoder: Decoder) delegates to it.

To learn more about how Codable works, visit here.

Related