Question or problem in the Swift programming language:
Consider a protocol and a class that implements it:
protocol MyProtocol { var x: Int { get } } class MyClass : MyProtocol { var x: Int = 5 }
I have an array of type [MyClass] and I wish to assign it to a variable of type [MyProtocol]. However, this causes a error when attempted in Playground (XCode 6.3, Swift 1.2):
var classArr: [MyClass] = [MyClass(), MyClass()] var protocolArrA: [MyProtocol] = classArr // Causes error: EXC_BAD_INSTRUCTION var protocolArrB: [MyProtocol] = classArr as [MyProtocol] // Causes error: EXC_BAD_INSTRUCTION var protocolArrC: [MyProtocol] = [MyProtocol](classArr) // Causes error: Cannot find an initializer for type [MyProtocol[ that accepts an argument list of type [MyClass]
What is the correct way to make this assignment in Swift?
P.S. Interestingly, when using a base class instead of a protocol, the expressions for protocolArrA and protocolArrB work without error.
It is also interesting to note that assigning a newly created instance of [MyClass] also works well:
var protocolArrD: [MyProtocol] = [MyClass]() // A-OK!
How to solve the problem:
Solution 1:
You can use map to cast each element to the desired type:
protocol MyProtocol { var x: Int { get } } class MyClass : MyProtocol { var x: Int = 5 } var classArr: [MyClass] = [MyClass(), MyClass()] var protocolArrA:[MyProtocol] = classArr.map{$0 as MyProtocol} var andBack:[MyClass] = protocolArrA.map{$0 as! MyClass}
Note, Swift is able to infer all of the array types above, so this can be written more succinctly as:
var classArr = [MyClass(), MyClass()] var protocolArrA = classArr.map{$0 as MyProtocol} var andBack = protocolArrA.map{$0 as! MyClass}
Solution 2:
Try this
@objc protocol MyProtocol { var x: Int { get } } class MyClass : MyProtocol { @objc var x: Int = 5 }
Both works if using @objc
var classArr: [MyClass] = [MyClass(), MyClass()] var protocolArrA: [MyProtocol] = classArr var protocolArrB: [MyProtocol] = classArr as [MyProtocol]