问题
So, I'm using realm and I have the following relationship between two models: A unit has many tests
:
// Unit model
class Unit: Object, Decodable {
@objc dynamic var id: String = ""
...
let tests = List<Test>()
enum CodingKeys: String, CodingKey {
case id
...
//case tests = "complete_control_tests"
}
convenience required init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
...
if let arr = try container.decodeIfPresent(Array<Test>.self, forKey: .tests) {
tests.append(objectsIn: arr)
} else {
self.tests.append(objectsIn: [])
}
}
}
// Test model
class Test: Object, Decodable {
@objc dynamic var id: String = ""
@objc dynamic var room_control_id: String = ""
enum CodingKeys: String, CodingKey {
case id
case room_control_id = "room_control_id"
}
}
When the tests
property is commented, I can properly parse the json output for that model. But then when I uncommented it, I have the following errors:
Swift.Encodable:12:17: Protocol requires function 'encode(to:)' with type 'Encodable'
Models/Unit.swift:27:6: Cannot automatically synthesize 'Encodable' because 'List<Test>' does not conform to 'Encodable'
Is there a way to make Codable and Realm play nice?
回答1:
There are several issues with your code. First of all, if you only want to implement the init(from:)
method, but not the encode
method, declare conformance to Decodable
rather than Codable
. Secondly, you need to implement CodingKeys
when creating your own init(from:)
method and you also need to call a designated initializer of your class from a convenience initializer.
There's also no need for the else
clause in the initializer, since tests
is initialized as an empty List
already and appending an empty array to it makes no sense.
class Unit: Object, Decodable {
@objc dynamic var id: String = ""
let tests = List<Test>()
private enum CodingKeys: String, CodingKey {
case id, tests
}
convenience required init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
if let arr = try container.decodeIfPresent(Array<Test>.self, forKey: .tests) {
tests.append(objectsIn: arr)
}
}
}
回答2:
The first error message clearly states that if you implement custom init
method (decode) you have also to implement encode(to:)
(encode) to conform to the protocol.
If you are only decoding the object and you don't need to encode it adopt only Decodable.
Otherwise implement encode(to:)
.
To solve the second error declare the CodingKeys
explicitly.
回答3:
I've found why it's not working. It was Xcode's cache. I've deleted the contents of Xcode Derived data folder and now it's compiling and parsing the json correctly.
Sorry, folks !
来源:https://stackoverflow.com/questions/48619049/list-is-not-conforming-to-encodable