小编典典

Swift:无法将值分配给协议的属性?

swift

A类提供一个字符串值。类B在其内部具有两个A类型的成员,并提供一个计算属性“ v”来选择其中之一。

class A {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B {
    var v1: A?
    var v2: A = A(value: "2")

    private var v: A {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue
        }
    }
}

这段代码很简单,可以正常工作。由于A和B都具有成员“值”,因此我将其设为这样的协议:

protocol ValueProvider {
    var value: String {get set}
}

class A: ValueProvider {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B: ValueProvider {
    var v1: ValueProvider?
    var v2: ValueProvider = A(value: "2")

    private var v: ValueProvider {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue // Error: Cannot assign to the result of the expression
        }
    }
}

如果我更改以下代码

v.value = newValue

var v = self.v
v.value = newValue

它再次起作用!

这是Swift的错误,还是协议属性的特殊之处?


阅读 244

收藏
2020-07-07

共1个答案

小编典典

您必须将协议定义为class协议:

protocol ValueProvider : class {
    var value: String {get set}
}

然后

var value: String {
    get { return v.value }
    set { v.value = newValue }
}

编译并按预期方式工作(即,将新值分配给v1if v1 != nil所引用的对象,v2否则分配给否则所引用的对象)。

v是类型的只读计算属性ValueProvider。通过将协议定义为类协议,编译器知道这v引用类型 ,因此v.value
即使引用本身是常量,也可以修改其属性。

您的初始代码示例有效,因为该 v属性具有A引用类型的类型。

和您的解决方法

set {
    var tmp = v1 ?? v2
    tmp.value = newValue
}

之所以起作用,是因为可以在任何情况下(值类型或引用类型)设置 变量的 (读写)属性。

2020-07-07