通过只读属性

时间:2016-04-28 15:31:49

标签: swift protocols

有人可以告诉我为什么当Swift仅用于访问对象(协议)以设置其中一个属性时,为什么要调用属性的setter?第一个例子显示了如果我没有将间接对象声明为可设置的错误:

protocol AProtocol {
    var name: String { get set }
}

class AnImplementation: AProtocol {
    var name = ""
}

class AParent {
    var test = AnImplementation()
}

class AChild {
    var parent: AParent!

    var test: AProtocol {
        get { return parent.test }
        // Note: Not settable
    }
}

var parent = AParent()
var child = AChild()
child.parent = parent

child.test.name = "Hello world!"  // Error: Cannot assign to property : 'test' is a get-only property
print(child.test.name)

如果我给它一个setter,它会编译并运行但它会调用setter:

protocol AProtocol {
    var name: String { get set }
}

class AnImplementation: AProtocol {
    var name = ""
}

class AParent {
    var test = AnImplementation()
}

class AChild {
    var parent: AParent!

    var test: AProtocol {
        get { return parent.test }
        set(newTest) { print("Shouldn't be here!") }
    }
}

var parent = AParent()
var child = AChild()
child.parent = parent

child.test.name = "Hello world!"
print(child.test.name)

输出是:

Shouldn't be here!
Hello world!

我不确定我在这里不理解什么。我想我可以给它一个空的二传手,但我想了解它的原因。

非常感谢任何信息!

2 个答案:

答案 0 :(得分:2)

将您的协议声明更改为:

protocol AProtocol:class {
    var name: String { get set }
}

否则,默认情况下它将被视为值类型。更改值类型的属性将替换值类型实例(如setter观察者所示)。如果引用是let引用,则无法执行此操作。

答案 1 :(得分:2)

这可能是因为编译器不知道AChild.test是类还是值类型。使用类没有问题,但是分配给name的值类型也会创建对test的赋值(值复制行为)。将APProtocol标记为class协议将解决问题。

要扩展,当编译器不确定test是值还是类类型时,它将使用以下重写child.test.name = "Hello world!"

var tmp = child.test
tmp.test = "Hello world!"
child.test = tmp

因为它适用于类和值类型。