10

At the moment, I have a struct that conforms to Codable:

public struct Preference: Codable {

    public let id: String

}

When I try to initialize the object using the following:

let preference = Preference(id: "cool")

I get the following error:

Argument type 'String' does not conform to expected type 'Decoder'

How can I fix this issue and initialize the struct properly?

Adam Cooper
  • 867
  • 1
  • 6
  • 23
  • 1
    Strange, that compiles without problems in my Xcode 9.2. – Martin R Jan 09 '18 at 19:29
  • 1
    I also can't reproduce this. I suspect this is not the actual code. What line does this error appear on? Is `Preference` have exactly this one property in your code? – Rob Napier Jan 09 '18 at 19:31
  • 2
    Start a new project and try to construct a [mcve]. – Martin R Jan 09 '18 at 19:33
  • @RobNapier This is actual code and the error occurs when trying to initialize the object. – Adam Cooper Jan 09 '18 at 19:37
  • Perhaps you autocompleted to `let preference = Preference(from: "cool")` ? That would give you that error. Maybe you forgot to change it to the correct initializer or changed it and the compiler is slow in catching up? Maybe try a clean? – ekreloff Jan 09 '18 at 19:38
  • @ekreloff if you use the "from:" initializer you've got to then force cast the string to conform to decoder. – Adam Cooper Jan 09 '18 at 19:53
  • This compiles and runs correctly. Must be something else in your codebase? Xcode version? – picciano Jan 09 '18 at 20:21
  • @AdamCooper, I'm just suggesting the circumstance when that error would appear. – ekreloff Jan 10 '18 at 02:41
  • So apparently the type is defined in a framework (module), and the constructor called from outside of the module? – That would be an important information to add to the question. – Martin R Jan 10 '18 at 08:09

1 Answers1

20

When struct is created without explicit initializer

public struct Preference {
    public let id: String
}

it gets internal init(id: String) initializer for free. Internal means that using it from another target will result in compiler error.

Adding Decodable to your struct also adds public init(from: Decoder) initializer to this struct.

So initial struct is equivalent to the following

public struct Preference: Codable {
    public let id: String

    internal init(id: String) {
        self.id = id
    }

    public init(from: Decoder) {
        // generated decoding code
    }
}

When you try to create an instance using Preference(id: "cool") from another target there is only one public initializer: the one with the decoder. Compiler tries to use it by casting String to Decoder and it fails.

To resolve the original issue you need to add public init(id: String) initializer explicitly.

Maxim Kosov
  • 1,930
  • 10
  • 19