RawRepresentable Conformance Leads to Crash

The following code snippet works exactly as expected:

import Foundation

struct S: Codable {
    
    let i: Int
    let j: String
    
    init(i: Int, j: String) {
        self.i = i
        self.j = j
    }
    
    init?(rawValue: String) {
        guard
            let data = rawValue.data(using: .utf8),
            let s = try? JSONDecoder().decode(S.self, from: data)
        else { return nil }
        
        self = s
    }
    
    var rawValue: String {
        guard
            let data = try? JSONEncoder().encode(self),
            let string = String(data: data, encoding: .utf8)
        else { return "" }
        
        return string
    }
}

let s = S(i: 1, j: "String")
let t = S(rawValue: s.rawValue)!
print(t == s) // true

If I conform S to RawRepresentable though I get:

error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x16a92fff0).

I've changed nothing except adding : RawRepresentable in the declaration of S.
What is causing this crash?

If I'm not mistaken, when you have a Codable and RawRepresentable type, the rawValue is used to encode/decode the value. If that's the case, you're incurring in an endless recursion by encoding/decoding in the rawValue definition.

Edit: I'm not mistaken.

2 Likes

Thanks! That seems to be the problem.

Adding manual en-/decoding fixed it:

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(i, forKey: .i)
        try container.encode(j, forKey: .j)
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        i = try container.decode(Int.self, forKey: .i)
        j = try container.decode(String.self, forKey: .j)
    }
Terms of Service

Privacy Policy

Cookie Policy