Swift:为什么带有 setter 的变量也必须有 getter?

Swift: Why does a variable with a setter must also have a getter?

快速提问:为什么?


上下文:

我正在使用 Swinject 依赖注入将 small-s 单例模型 类 添加到我的视图中,因此:

defaultContainer.registerForStoryboard( MyViewController.self )
{
    responder, viewController in
    viewController.proxy = responder.resolve( MyProxy.self )!
}

我想通过使用计算 属性 来防止意外覆盖此单例实例的风险:

private var _proxy: MyProxy!

var proxy: MyProxy 
{ 
    set { if _proxy == nil { _proxy = newValue } } 
}

但是。我不能。因为我必须同时声明一个getter.

令人沮丧!

目前我正在使用以下 hack。但真的...

var proxy: MyProxy?
{
    get { return nil }
    set { if _proxy == nil && newValue != nil { _proxy = newValue } }
}

为什么你不能 return _proxy 在你的 getter 中?那有什么关系?如果你害怕暴露你的 getter ,你可以将你的 getter 设置为私有,这样只在包含 class.

的地方暴露它
private(get) var proxy: MyProxy? {
  set { if _proxy == nil && newValue != nil { _proxy = newValue } }
}

目前你只能使用属性观察者didSetwillSet

快速问题“为什么?”的快速回答:

get(或 set)添加到 属性 后,它会变成 Computed Property。计算属性可能是read-only,因此只需要get之三,但它们可能 为 write-only。所以如果你把一个setter加到一个属性,你就把它变成了一台电脑属性因此你必须 也添加一个 getter。

编辑: 根据评论,为什么计算属性可以是 read-only,而不是 write-only?

我找不到官方文档来支持这一点,所以以下解释完全基于我的逻辑观点:

计算属性不在其变量上存储实际数据;相反,他们 计算 要显示的数据。

var a:Int = 5 // Stored property
var timesTen:Int { // Computed Property
    get {
        return a * 10
    }
}

从上面的例子来看:aStored 属性。因此,它的get方法自动取returnsa的值。现在想想timesTen:它的值是多少?由于它不在 timesTen 变量中存储任何值,因此您 必须告诉计算 属性 如何以及从何处从 读取其 "value"。所以这就是为什么您不能将计算的 属性 用于 writing-only 目的。


解决方法/如何避免

对于简单的属性,您可以使用 didSetwillSet 来达到预期目的:

var proxy: MyProxy?
{
    willSet { if _proxy == nil && newValue != nil { _proxy = newValue } }
}

如果您正在使用 Swift 2.x,您可以使用 guard 语句来获得更清晰的代码:

var proxy: MyProxy?
{
    willSet { 
         guard (_proxy == nil && newValue != nil) else { return }
         _proxy = newValue
    }
}

另一个观察结果

如果_proxy不需要成为private,您可以完全删除它,只使用一个variable/property而不是两个:

var proxy: MyProxy!
{
    willSet { 
         guard (proxy == nil && newValue != nil) else { return }
         // By not preventing `willSet` to continue, `newValue` will automatically assigned to `proxy`
    }
}