I ran into what I think is a strange error in may app. At the bottom of this question is complete code the reproduces what I am seeing in my app, but here is a quick demonstration.
I create two instances of the same class, one is declared as an optional conforming to a protocol the other as an optional of a concrete class
For both I can set the computed property via option chaining ie:
anOptionalInstance?.someComputedProperty = ....
for the concrete version I can set the property by unwrapping the optional
if let anInstance = anOptionalInstance {
anInstance.someComputedProperty = ....
}
For the polymorphic version, I get an error message that says I can't set the property on the instance.
Below is a complete file that reproduces the issue I am seeing.
Can anyone explain what is happening here?
struct MyStruct {
var someMember: String
}
protocol MyProtocol {
var myVar: MyStruct { get set }
}
class MyType: MyProtocol {
var myVar: MyStruct {
get {
return MyStruct(someMember: "some string")
}
set {
println(newValue)
}
}
}
class UsingClass {
var anInstanceOfMyType: MyProtocol?
var anOtherInstanceOfMyType: MyType?
func someMethod() {
anInstanceOfMyType = MyType()
anInstanceOfMyType?.myVar = MyStruct(someMember: "blah")
if let anInstanceOfMyType = anInstanceOfMyType {
// The following line produces this error :Cannot assign to 'myVar' in 'anInstanceOfMyType'
anInstanceOfMyType.myVar = MyStruct(someMember: "blah blah")
}
anOtherInstanceOfMyType = MyType()
anOtherInstanceOfMyType?.myVar = MyStruct(someMember: "blah")
if let anOtherInstanceOfMyType = anOtherInstanceOfMyType {
anOtherInstanceOfMyType.myVar = MyStruct(someMember: "blah blah")
}
}
}
The problem does happen because you are trying to change the property of the constant anInstanceOfMyType
which type is MyProtocol
.
anInstanceOfMyType
is a constant?At the first line of UsingClass
, anInstanceOfMyType
is actually declared as var
. However with the Conditional Unwrapping
a constant with name anInstanceOfMyType
is created, and you are trying to change a property of that constant
anInstanceOfMyType
references an instance of a class, so I should be able to change its properties even if it's a constantSince anInstanceOfMyType
has MyProtocol
as type, it could contain a struct
or a reference an instance of a class
. So the compiler does apply the safer approach and avoid you to change its properties.
Limit protocol adoption to class types (and not structures or enumerations) by adding the class keyword to a protocol’s inheritance list. The class keyword must always appear first in a protocol’s inheritance list, before any inherited protocols:
protocol MyProtocol: class {
var myVar: MyStruct { get set }
}
or
If MyProtocol
is updated to extend AnyObject
protocol MyProtocol : AnyObject {
var myVar: MyStruct { get set }
}
then becomes clear that anInstanceOfMyType
must refer an instance of a class, in this case your code does compile.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments