Implementing RawRepresentable for a DictionaryType has broken my Test target build. Not sure how to fix things...

For my app I've created a Dictionary that I want to persist using AppStorage In order to be able to do this, I added RawRepresentable conformance for my specific type of Dictionary. (see code below)

typealias ScriptPickers = [Language: Bool]
extension ScriptPickers: @retroactive RawRepresentable where Key == Language, Value == Bool {
    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8),
              let result = try? JSONDecoder().decode(ScriptPickers.self, from: data)
        else {
            return nil
        }
        self = result
    }
    
    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self),   // data is  Data type
              let result = String(data: data, encoding: .utf8) // coerce NSData to String
        else {
            return "{}"  // empty Dictionary represented as String
        }
        return result
    }
}
public enum Language: String, Codable, {
    
    case en = "en"
    case fr = "fr"
    case ja = "ja"
    case ko = "ko"
    case hr = "hr"
    case de = "de"
}

This all works fine in my app, however trying to run any tests, the build fails with the following:

Conflicting conformance of 'Dictionary<Key, Value>' to protocol 'RawRepresentable'; there cannot be more than one conformance, even with different conditional bounds

But then when I comment out my RawRepresentable implementation, I get the following error when attempting to run tests:

Value of type 'ScriptPickers' (aka 'Dictionary<Language, Bool>') has no member 'rawValue'

I hope Joseph Heller is out there somewhere chuckling at my predicament

any/all ideas greatly appreciated

Answered by DTS Engineer in 825046022

I’m not sure I fully understand your final destination, but you’ve definitely strayed from the path. Consider this:

typealias ScriptPickers = [Language: Bool]
extension ScriptPickers: @retroactive RawRepresentable …

This is bad. ScriptPickers is a type alias, not a new type. So your extension is conforming a type you don’t own (Dictionary) to a protocol you don’t own (RawRepresentable). That is most definitely wrong. Swift tried to warn you about this by forcing you to add the @retroactive attribute. See SE-0364 Warning for Retroactive Conformances of External Types for more on that.

How you fix this kinda depends, but I suspect that your best option is to make ScriptPickers a struct with a property that is the actual dictionary. You ‘own’ the ScriptPickers struct, and thus you can add a conformance to RawRepresentable without running into problems.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

I’m not sure I fully understand your final destination, but you’ve definitely strayed from the path. Consider this:

typealias ScriptPickers = [Language: Bool]
extension ScriptPickers: @retroactive RawRepresentable …

This is bad. ScriptPickers is a type alias, not a new type. So your extension is conforming a type you don’t own (Dictionary) to a protocol you don’t own (RawRepresentable). That is most definitely wrong. Swift tried to warn you about this by forcing you to add the @retroactive attribute. See SE-0364 Warning for Retroactive Conformances of External Types for more on that.

How you fix this kinda depends, but I suspect that your best option is to make ScriptPickers a struct with a property that is the actual dictionary. You ‘own’ the ScriptPickers struct, and thus you can add a conformance to RawRepresentable without running into problems.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Implementing RawRepresentable for a DictionaryType has broken my Test target build. Not sure how to fix things...
 
 
Q