swift - 在 swift 中,为什么我可以通过可选链接设置多态变量的计算属性,而不是在展开的可选上?

标签 swift

我在 may app 中遇到了一个我认为是奇怪的错误。这个问题的底部是完整的代码,它重现了我在我的应用程序中看到的内容,但这里是一个快速演示。


我创建了同一个类的两个实例,一个被声明为符合协议(protocol)的可选,另一个被声明为具体类的可选

对于这两者,我都可以通过选项链来设置计算属性,即:

anOptionalInstance?.someComputedProperty = ....

对于具体版本,我可以通过展开可选的来设置属性

if let anInstance = anOptionalInstance {
  anInstance.someComputedProperty = ....
}

对于多态版本,我收到一条错误消息,提示我无法在实例上设置属性。


下面是一个完整的文件,它重现了我所看到的问题。

谁能解释一下这里发生了什么?

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

最佳答案

问题确实发生了,因为您试图更改类型为 MyProtocol常量 anInstanceOfMyType 的属性。

1。为什么 anInstanceOfMyType 是常量?

UsingClass的第一行,anInstanceOfMyType实际上被声明为var。但是,使用 Conditional Unwrapping 会创建名称为 anInstanceOfMyType 的常量,而您正试图更改该常量的属性

2。好的,但是 anInstanceOfMyType 引用了一个类的实例,所以我应该能够更改它的属性,即使它是一个常量

因为 anInstanceOfMyTypeMyProtocol 作为类型,它可以包含一个 struct 或一个引用 一个类的实例。 因此编译器确实应用了更安全的方法并避免您更改其属性。

解决方案

通过将 class 关键字添加到协议(protocol)的继承列表中,将协议(protocol)采用限制为类类型(而不是结构或枚举)。 class 关键字必须始终出现在协议(protocol)的继承列表中的第一个位置,在任何继承的协议(protocol)之前:

protocol MyProtocol: class {
  var myVar: MyStruct { get set }
}

如果 MyProtocol 更新为扩展 AnyObject

protocol MyProtocol : AnyObject {
    var myVar: MyStruct { get set }
}

然后很明显 anInstanceOfMyType 必须引用一个类的实例,在这种情况下您的代码可以编译。

关于swift - 在 swift 中,为什么我可以通过可选链接设置多态变量的计算属性,而不是在展开的可选上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32300734/

相关文章:

swift - 使用 PromiseKit 和 Alamofire 时跟踪进度

ios - 如何在 swift 中访问嵌套 JSON 对象内的值?

ios - Scenekit PhysicEngine跟随滚球

cocoa - Swift 协议(protocol) : method does not override any method from its superclass

ios - 无法获取另一个类中 var 的值

Swift Siesta 重定向对失败的响应

ios - 如何从嵌入在 UIScrollView 中的 UiView 中嵌入的 CollectionView 接收触摸事件

ios - 如何从 subview Controller 中找到选项卡栏方案中选定的选项卡

ios - 将元素紧密分组

Swift 字典排序