Below I have pasted code which you should be able to paste into a Swift 3 playground and see the error.
I have a protocol defined and create an empty array of that type. I then have a class which conforms to the protocol which I try to append to the array but I get the below error.
protocol MyProtocol {
var text: String { get }
}
class MyClass: MyProtocol {
var text = "Hello"
}
var collection = [MyProtocol]()
var myClassCollection = [MyClass(), MyClass()]
collection.append(myClassCollection)
argument type '[MyClass]' does not conform to expected type 'MyProtocol'
Note that collection += myClassCollection returns the following error:
error: cannot convert value of type '[MyProtocol]' to expected argument type 'inout _'
This was working in earlier versions of Swift.
The only solution I have found so far is to iterate and add each element to the new array like so:
for item in myClassCollection {
collection.append(item)
}
Any help appreciated, thanks!
EDIT
The solution as show below is:
collection.append(contentsOf: myClassCollection as [MyProtocol])
The real issue is a misleading compiler error when you are missing "as [MyProtocol]"
The compiler error reads:
error: extraneous argument label 'contentsOf:' in call
collection.append(contentsOf: myClassCollection)
This error causes users to remove contentsOf:
from the code which then causes the error I first mentioned.
append(_ newElement: Element)
appends a single element.
What you want is append(contentsOf newElements: C)
.
But you have
to convert the [MyClass]
array to [MyProtocol]
explicitly:
collection.append(contentsOf: myClassCollection as [MyProtocol])
// or:
collection += myClassCollection as [MyProtocol]
As explained in Type conversion when using protocol in Swift, this
wraps each array element into a box which holds "something that conforms to MyProtocol
", it is not just a reinterpretation
of the array.
The compiler does this automatically for a single value (that is why
for item in myClassCollection {
collection.append(item)
}
compiles) but not for an array. In earlier Swift versions, you
could not even cast an entire array with as [MyProtocol]
, you
had to cast each individual element.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With