trundrumbalind trundrumbalind - 1 year ago 53
Swift Question

Swift dynamictype initialisation with dynamic protocol type

I have a number of structs which implement a

protocol. This defines that they must have a variable
which conforms to
protocol to provide a way to initialise them with json via
init(json: [String: AnyObject]
. I'm trying to provide a way to dynamically instantiate these, with JSON, providing the right type of
and assign it to the struct's
variable. However, I'm getting a
Argument labels '(json:)' do not match any available overloads
error when trying to instantiate them via their

protocol Resource {

associatedtype ExtendedInfoTypeAlias: ExtendedInfo

var extendedInfo: ExtendedInfoTypeAlias? { get set }

protocol ExtendedInfo {
init(json: [String: AnyObject])

struct User: Resource {

typealias ExtendedInfoTypeAlias = UserExtendedInfo

let name: String = "Name"
var extendedInfo: UserExtendedInfo?

struct UserExtendedInfo: ExtendedInfo {

let age: Int?

init(json: [String: AnyObject]) {
age = json["age"] as? Int

let user = User()
let sampleJSON = ["age": 50]

let userExtendedInfo = user.extendedInfo.dynamicType.init(json: sampleJSON) // Argument labels '(json:)' do not match any available overloads
user.extendedInfo = userExtendedInfo

Any ideas guys? Thanks

Answer Source

First of all, you don't need to explicitly define the type of ExtendedInfoTypeAlias in your struct implementation – you can just let it be inferred by the type you provide for extendedInfo.

struct User: Resource {
    let name: String = "Name"
    var extendedInfo: UserExtendedInfo?

Second of all, you can just use the protocol's associated type of your given struct's dynamicType in order to use your given initialiser. For example:

user.extendedInfo = user.dynamicType.ExtendedInfoTypeAlias.init(json: sampleJSON)
print(user.extendedInfo) // Optional(Dynamic_Protocols.UserExtendedInfo(age: Optional(50)))

As for why your current code doesn't work, I suspect it's due to the fact that you're getting the dynamicType from an optional – which is preventing you from calling your initialiser on it.

I did find that the following works (even when extendedInfo is nil, although I have no idea why):

user.extendedInfo = user.extendedInfo!.dynamicType.init(json: sampleJSON)

If someone knows exactly why this works, I'd love to know, but in the meantime I would definitely opt for the previous way of doing it!