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

optional closure property in Swift

From Dev

Optional Binding on Implicitly Unwrapped Optional

From Dev

swift optional chaining with cast

From Dev

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

From Dev

Value of optional type CGFloat not unwrapped error in Swift

From Dev

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

From Dev

Optional Chaining or ternary expression in Swift?

From Dev

Swift optional variable not set using Xcode 6.1

From Dev

Why is a Swift implicitly unwrapped optional `nil`?

From Dev

Swift unary operator with implicitly unwrapped optional

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 2: !, ? -" Value of optional type "..." not unwrapped"

From Dev

Why can I declare a variable without writing optional mark?

From Dev

Swift - Check nil of an unwrapped optional variable

From Dev

Swift 3.0 Optional Chaining

From Dev

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

From Dev

Optional chaining with Swift strings

From Dev

Optional chaining and Array in swift

From Dev

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

From Dev

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

From Dev

Swift Optional Unwrapped still crashes

From Dev

Swift unary operator with implicitly unwrapped optional

From Dev

Swift Optional Type not Unwrapped

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

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

From Dev

Swift 3: Meaning of parenthesis around unwrapped optional

From Dev

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

From Dev

Implicitly unwrapped optional from init!() in Swift 3.1

From Dev

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

Related Related

  1. 1

    optional closure property in Swift

  2. 2

    Optional Binding on Implicitly Unwrapped Optional

  3. 3

    swift optional chaining with cast

  4. 4

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

  5. 5

    Value of optional type CGFloat not unwrapped error in Swift

  6. 6

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

  7. 7

    Optional Chaining or ternary expression in Swift?

  8. 8

    Swift optional variable not set using Xcode 6.1

  9. 9

    Why is a Swift implicitly unwrapped optional `nil`?

  10. 10

    Swift unary operator with implicitly unwrapped optional

  11. 11

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

  12. 12

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

  13. 13

    Why can I declare a variable without writing optional mark?

  14. 14

    Swift - Check nil of an unwrapped optional variable

  15. 15

    Swift 3.0 Optional Chaining

  16. 16

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

  17. 17

    Optional chaining with Swift strings

  18. 18

    Optional chaining and Array in swift

  19. 19

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

  20. 20

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

  21. 21

    Swift Optional Unwrapped still crashes

  22. 22

    Swift unary operator with implicitly unwrapped optional

  23. 23

    Swift Optional Type not Unwrapped

  24. 24

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

  25. 25

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

  26. 26

    Swift 3: Meaning of parenthesis around unwrapped optional

  27. 27

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

  28. 28

    Implicitly unwrapped optional from init!() in Swift 3.1

  29. 29

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

HotTag

Archive