Assign a protocol compliant type programatically

I have a large number of protocol compliant types which I am processing using an array, something like this:

protocol Thing {
	func multiply(_ n: Int) -> Int
}

struct One: Thing {
	func multiply(_ n: Int) -> Int { n * 1 }
}

struct Two: Thing {
	func multiply(_ n: Int) -> Int { n * 2 }
}

var thingArray: [Thing] = []
let name = "Two"

switch name {
case "One":
	thingArray.append(One())
case "Two":
	thingArray.append(Two())
...
default:
	()
}

This code works fine, but the problem is that there will ultimately be a large number of compliant types so the switch block will become large.

My question is this: Is there a way in Swift of assigning the protocol based on the value of a variable? something like this:

thingArray.append(Struct(name)())

It would be nice to replace the entires switch block with a single line.

If you want to avoid the switch (with which any you will have to loop through all names), why not just :

var thingArray: [Thing] = [One(), Two()]

If you want to build the array depending of name, I did try using any:

var thingArray: [any Thing] = []
let dict : [String : Any] = ["One": One.self, "Two": Two.self]
let name = "Two"

if let theStruct = dict[name] as? Thing {
    let item = theStruct
    print(theStruct)  // Gives Two
    thingArray.append(theStruct) 
}

But that does not add an instance of struct as you apparently expect.

It would be much easier with classes instead of Protocols…

See this thread for discussion on arrays of protocols: https://developer.apple.com/forums/thread/713004

Thanks for your reply. The structs are read from a file, so the array can't be populated statically.

I could use classes instead, but wouldn't I still need a switch to choose the appropriate subclass?

No, that should work without a switch.

I tested this, hope it is what you are looking for. Otherwise, let's hope some Swift deep expert will react to this thread.

I had to add a Default class to handle default case…

protocol Thing {
    func multiply(_ n: Int) -> Int
}

class One: Thing {
    func multiply(_ n: Int) -> Int { n * 1 }
}

class Two: Thing {
    func multiply(_ n: Int) -> Int { n * 2 }
}

class Default: Thing {
    func multiply(_ n: Int) -> Int { 0 }
}

var thingArray: [Any] = []
let dict : [String : Any] = ["One": One(), "Two": Two()]
let name = "Two"

if let theStruct = dict[name] {
    let item = theStruct
    thingArray.append(theStruct)
} else {
    thingArray.append(Default())
}

let result = (thingArray[0] as! Thing).multiply(10)
print("result", result)

Gives

result 20

Understood, that's a clever use of a dictionary. Thanks - that solves my issue

Assign a protocol compliant type programatically
 
 
Q