为什么默认情况下将 Swift 符合协议的值视为值类型?

Why Swift protocol conforming values are treated as Value types by default?

我有一个协议,它只描述了一个接口。

protocol SampleProtocol {
var message: String? { get set }}

为什么编译器总是将符合要求的 value/object 视为值类型?

示例,

 // Protocol value usage
import Foundation


protocol SampleProtocol {
    var message: String? { get set }
}

final class SampleObject: SampleProtocol {
    var message: String?
}


final class Controller {

    var sampleValue: SampleProtocol! {
        didSet {
            print("New value has been set")
        }
    }
}


let controller = Controller()
controller.sampleValue = AlphaObject() // Correctly prints "New value has been set"
controller.sampleValue.message = "New message" // Prints again "New value has been set", like for value types

您的协议 SampleProtocol 可能会被 classstruct 采用。 Swift 正在使用值类型的行为,它是限制性更强的类型,直到您告诉它该协议将仅由 class 引用类型使用。

将对 AnyObject 的一致性添加到您的协议中以获得引用类型行为:

protocol SampleProtocol: AnyObject {
    var message: String? { get set }
}

有关详细信息,请参阅 The Swift 5.1 Programming Guide - Class-Only Protocols

指南注释:

Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics.


历史记录:使用class关键字:

在 Swift 4.0 之前,这是使用 class 关键字编写的:

protocol SampleProtocol: class {
    var message: String? { get set }
}

这暂时仍然有效,但它目前只是 AnyObject 的类型别名,可能会在 Swift 的更高版本中删除。

它不会创建对象的副本。在两个调用中它是同一个对象——如果你把 print(Unmanaged.passUnretained(sampleValue as AnyObject).toOpaque()) 放在 didSet 中你会看到地址是相同的。编译器不知道它正在处理值类型或引用类型。如果你像这样在协议声明中放置一个 class 关键字:

protocol SampleProtocol: class { ... }

didSet 将被调用一次,因为编译器知道它是引用类型并且不会重新分配引用。 我想生成的不同设置器取决于 属性

的类型