我们可以在Swift中编辑 "let" 协议属性的属性吗?

8 浏览
0 Comments

我们可以在Swift中编辑 "let" 协议属性的属性吗?

我有一个类似这样的代码(在一个playground中运行):

protocol ServiceProtocol {

var enabled: Bool { get set }

}

class Service: ServiceProtocol {

var enabled: Bool = false

}

class A {

let service = Service()

}

class B {

let service: ServiceProtocol = Service()

}

let a = A()

let b = B()

a.service.enabled = false

b.service.enabled = false // <-- 错误出现在这里:无法分配给属性:'service' 是一个 'let' 常量

如果我将service引用为Service(类A),一切都按预期工作。但在类B中,service是一个ServiceProtocol,我遇到了错误:

无法分配给属性:'service' 是一个 'let' 常量

对我来说这是荒谬的,因为我并没有尝试给service分配任何东西:我只是尝试给service的属性分配一个值。由于enabledget set,我应该能够像在A中一样进行赋值。

如果我在类B中将service声明为var,错误就消失了。

有什么想法吗?

0
0 Comments

在Swift中,可以使用类、结构体和枚举来实现协议。由于编译器无法确定实现协议的类型是引用类型还是值类型,因此会出现问题。为了解决这个问题,可以将协议限定为只适用于类,这样代码就能正常工作了。

protocol ServiceProtocol: AnyObject {

var enabled: Bool { get set }

}

现在,下面的代码可以编译通过了:

b.service.enabled = false

非常好,问题解决了!不过,错误信息可能还有改进的空间

我想在这里提醒一下,AnyObject表示的是Objective-C对象。虽然大多数情况下这不是一个问题,但我认为这是一个重要的知识点。如果想保持它作为一个“仅限于Swift”的对象,可以将协议标记为protocol ServiceProtocol: class {}

我个人认为,使用class而不是AnyObject会更加清晰地表明协议需要符合的类型必须是类,特别是对于刚接触Swift的人来说。

那是完全错误的。实际上,class只是AnyObject的类型别名。你把AnyObjectNSObject弄混了。AnyObject只是一个Swift的协议,所有的类都隐式地符合它,它并不表示Objective-C对象。

只是提一下,“class vs AnyObject protocol”在这里有讨论:stackoverflow.com/q/30176814/1187415(包含了一些指向Swift论坛的链接)。

是的,我认为你需要习惯于编译器的错误信息可能会让人感到困惑或误导:)

令人惊讶的误导,令人惊讶的描述。哇!

0