Swift – 协议扩展 – 属性默认值

假设我有以下协议:

protocol Identifiable { var id: Int {get} var name: String {get} } 

而且我有以下结构:

 struct A: Identifiable { var id: Int var name: String } struct B: Identifiable { var id: Int var name: String } 

正如你所看到的,我必须“符合”在结构A和结构B的可识别协议。但想象一下,如果我有更多的结构需要符合这个协议…我不想'复制/粘贴一致性(var id:Int,var name:String)

所以我创build了一个协议扩展

 extension Identifiable { var id: Int { return 0 } var name: String { return "default" } } 

有了这个扩展现在我可以创build一个符合可识别协议的结构,而不必实现两个属性:

 struct C: Identifiable { } 

现在的问题是,我不能为id属性或name属性设置一个值:

 var c: C = C() c.id = 12 // Cannot assign to property: 'id' is a get-only property 

发生这种情况是因为在可识别协议中,ID和名称只能被获取。 现在,如果我更改ID和名称属性{get set}我得到以下错误:

types“C”不符合协议“可识别”

发生这个错误是因为我没有在协议扩展中实现一个setter …所以我改变了协议扩展:

 extension Identifiable { var id: Int { get { return 0 } set { } } var name: String { get { return "default" } set { } } } 

现在错误消失了,但是如果我为id或name设置一个新的值,它会得到默认值(getter)。 当然, 二传手是空的

我的问题是: 我必须将哪些代码放在setter中? 因为如果我添加self.id = newValue它崩溃(recursion)。

提前致谢。

看来你想通过协议扩展将stored property添加到types。 然而,这是不可能的,因为扩展名不能添加存储的属性。

我可以告诉你几个select。

子类化(面向对象编程)

最简单的方法(可能你已经想象了)是使用类而不是结构。

 class IdentifiableBase { var id = 0 var name = "default" } class A: IdentifiableBase { } let a = A() a.name = "test" print(a.name) // test 

缺点:在这种情况下,您的A类需要inheritance自IdentifiableBase ,因为在Swift中不是多重inheritance,这将是唯一的A类将能够inheritance。

组件(面向协议的编程)

这种技术在游戏开发中非常stream行

 struct IdentifiableComponent { var id = 0 var name = "default" } protocol HasIdentifiableComponent { var identifiableComponent: IdentifiableComponent { get set } } protocol Identifiable: HasIdentifiableComponent { } extension Identifiable { var id: Int { get { return identifiableComponent.id } set { identifiableComponent.id = newValue } } var name: String { get { return identifiableComponent.name } set { identifiableComponent.name = newValue } } } 

现在你可以使你的types符合可Identifiable简单的写作

 struct A: Identifiable { var identifiableComponent = IdentifiableComponent() } 

testing

 var a = A() a.name = "test" print(a.name) // test 

协议和协议扩展function非常强大,但是对于只读属性和函数,它们往往是最有用的。

对于你想要完成的事情(存储属性的默认值),类和inheritance可能实际上是更优雅的解决scheme

就像是:

 class Identifiable { var id: Int = 0 var name: String = "default" } class A:Identifiable { } class B:Identifiable { } let a = A() print("\(a.id) \(a.name)") a.id = 42 a.name = "foo" print("\(a.id) \(a.name)") 

这就是为什么你不能设置属性。

该属性成为一个计算属性,这意味着它没有一个支持variables,如_x,就像在ObjC中那样。 在下面的解决scheme代码中,您可以看到xTimesTwo不存储任何内容,只是计算x的结果。

请参阅关于计算属性的官方文档。

你想要的function也可能是属性观察者。

Setter / getters与Objective-C中的不同。

你需要的是:

 var x:Int var xTimesTwo:Int { set { x = newValue / 2 } get { return x * 2 } } 

您可以修改setter / getters中的其他属性,这是他们的意思