5

How does one add Codable conformance to a class that needs to be isolated to the MainActor?

For example, the following code gives compiler errors:

@MainActor final class MyClass: Codable {
    var value: Int
    
    enum CodingKeys: String, CodingKey {
        case value
    }
    
    init(from decoder: Decoder) throws { // <-- Compiler error: Initializer 'init(from:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Decodable'
        let data = try decoder.container(keyedBy: CodingKeys.self)
        self.value = try data.decode(Int.self, forKey: .value)
    }
    
    func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Encodable'
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(value, forKey: .value)
    }
}

I'm definitely struggling to get my head around actors and @MainActor at the moment!

Philip Pegden
  • 1,732
  • 1
  • 14
  • 33
  • I had originally posted an answer that I've discovered is wrong - making `init(from decoder: Decoder`) `async` will allow `MyClass` to conform to `Decodable`, but I can't get `Encodable` conformance to work. – Philip Pegden Aug 11 '21 at 14:09
  • No, because those `async` functions are different from the ones that Encodable wants to call. – matt Sep 02 '21 at 14:21

1 Answers1

3

There isn't anything about the class you've provided that needs to be isolated to the main actor, so don't isolate the class as a whole. If there are other members that you have not shown us that do need to be isolated to the main actor, isolate them.

Example:

final class MyClass: Codable {
    private var value: Int
    @MainActor init(value: Int) {
        self.value = value
    }
    @MainActor func setMyValue(to newValue:Int) {
        self.value = newValue
    }
    @MainActor func getMyValue() -> Int {
        self.value
    }
    enum CodingKeys: String, CodingKey {
        case value
    }
    init(from decoder: Decoder) throws {
        let data = try decoder.container(keyedBy: CodingKeys.self)
        self.value = try data.decode(Int.self, forKey: .value)
    }
    func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Encodable'
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(value, forKey: .value)
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141