In swift, why can I set a computed property of a polymorphic variable via optional chaining, but not on an unwrapped optional?

nPn

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")
    }
  }
}
Luca Angeletti

The problem does happen because you are trying to change the property of the constant anInstanceOfMyType which type is MyProtocol.

1. Why 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

2. Ok but anInstanceOfMyType references an instance of a class, so I should be able to change its properties even if it's a constant

Since 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.

Solution

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.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

In swift, why can I set a computed property of a polymorphic variable via optional chaining, but not on an unwrapped optional?

From Dev

Swift - Check nil of an unwrapped optional variable

From Dev

Why is a Swift implicitly unwrapped optional `nil`?

From Dev

Swift Optional Type not Unwrapped

From Dev

Swift Optional Unwrapped still crashes

From Dev

Swift 3.0 Optional Chaining

From Dev

swift optional chaining with cast

From Dev

Optional chaining with Swift strings

From Dev

Optional chaining and Array in swift

From Dev

Why Wrapped Optional Values in Swift? Is it possible to set a variable as optional without declaring a type?

From Dev

Value of optional type CGFloat not unwrapped error in Swift

From Dev

Swift unary operator with implicitly unwrapped optional

From Dev

Swift 2: !, ? -" Value of optional type "..." not unwrapped"

From Dev

Swift unary operator with implicitly unwrapped optional

From Dev

Swift 3: Meaning of parenthesis around unwrapped optional

From Dev

Implicitly unwrapped optional from init!() in Swift 3.1

From Dev

Why the default type of the label is a forced unwrapped optional?

From Dev

Why the default type of the label is a forced unwrapped optional?

From Dev

Optional Chaining or ternary expression in Swift?

From Dev

optional chaining in Swift 3: why does one example work and not the other?

From Dev

Why can I declare a variable without writing optional mark?

From Dev

Why is the 'view' property of UIViewController not optional in Swift?

From Dev

Swift: Why all my optional variable looks like "Optional(305.502)"

From Dev

Optional Binding on Implicitly Unwrapped Optional

From Dev

Swift optional variable not set using Xcode 6.1

From Dev

Why assigning nil to an optional variable is true in Swift?

From Dev

Why assigning nil to an optional variable is true in Swift?

From Dev

Why am I getting a "Value of optional type UIFont not unwrapped", but unwrapping gives "unexpectedly found nil while unwrapping an optional"?

From Dev

optional closure property in Swift

Related Related

  1. 1

    In swift, why can I set a computed property of a polymorphic variable via optional chaining, but not on an unwrapped optional?

  2. 2

    Swift - Check nil of an unwrapped optional variable

  3. 3

    Why is a Swift implicitly unwrapped optional `nil`?

  4. 4

    Swift Optional Type not Unwrapped

  5. 5

    Swift Optional Unwrapped still crashes

  6. 6

    Swift 3.0 Optional Chaining

  7. 7

    swift optional chaining with cast

  8. 8

    Optional chaining with Swift strings

  9. 9

    Optional chaining and Array in swift

  10. 10

    Why Wrapped Optional Values in Swift? Is it possible to set a variable as optional without declaring a type?

  11. 11

    Value of optional type CGFloat not unwrapped error in Swift

  12. 12

    Swift unary operator with implicitly unwrapped optional

  13. 13

    Swift 2: !, ? -" Value of optional type "..." not unwrapped"

  14. 14

    Swift unary operator with implicitly unwrapped optional

  15. 15

    Swift 3: Meaning of parenthesis around unwrapped optional

  16. 16

    Implicitly unwrapped optional from init!() in Swift 3.1

  17. 17

    Why the default type of the label is a forced unwrapped optional?

  18. 18

    Why the default type of the label is a forced unwrapped optional?

  19. 19

    Optional Chaining or ternary expression in Swift?

  20. 20

    optional chaining in Swift 3: why does one example work and not the other?

  21. 21

    Why can I declare a variable without writing optional mark?

  22. 22

    Why is the 'view' property of UIViewController not optional in Swift?

  23. 23

    Swift: Why all my optional variable looks like "Optional(305.502)"

  24. 24

    Optional Binding on Implicitly Unwrapped Optional

  25. 25

    Swift optional variable not set using Xcode 6.1

  26. 26

    Why assigning nil to an optional variable is true in Swift?

  27. 27

    Why assigning nil to an optional variable is true in Swift?

  28. 28

    Why am I getting a "Value of optional type UIFont not unwrapped", but unwrapping gives "unexpectedly found nil while unwrapping an optional"?

  29. 29

    optional closure property in Swift

HotTag

Archive