9

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!
1
  • 1
    Managed to reproduce your problem. It seems a lot like a bug :-/ The manual cast via classArr.map{$0 as MyProtocol} could be a workaround. Commented Jun 8, 2015 at 11:10

2 Answers 2

10

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}
Sign up to request clarification or add additional context in comments.

Comments

1

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] 

1 Comment

classArr is of type [MyClass] on purpose. I don't want to re-define it as [MyProtocol]. The actual code is much more complex, and I distilled only the portions causing the problem (which is not context-dependant IMHO).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.