【问题标题】:Overriding getter in Swift覆盖 Swift 中的 getter
【发布时间】:2015-07-10 09:06:41
【问题描述】:

我有一种情况需要覆盖属性的 getter。

假设我们有:

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
}

我猜,没什么特别的。

现在,如果我尝试覆盖派生类中的 getter:

public class MyDerivedClass: MyBaseClass {
    public var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

我收到编译错误:无法使用只读属性“名称”覆盖可变属性

如果我尝试添加设置器并覆盖它:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
            super.name = newValue
        }
    }
}

我收到错误:覆盖 var 的 Setter 必须与其覆盖的声明一样可访问

如果我尝试以下操作:

public class MyDerivedClass: MyBaseClass {
    public internal(set) var name: String {
        get {
            return "Derived - \(super.name)"
        }
    }
}

然后,编译器崩溃了……

我怎样才能实现只覆盖getter?

【问题讨论】:

  • 只是为了澄清,您需要一个只能在内部设置但其值在这些维度之外基本上是只读的计算变量(名称):“内部访问使实体能够在内部使用来自其定义模块的任何源文件,但不在该模块之外的任何源文件中。在定义应用程序或框架的内部结构时,通常使用内部访问。而 _name 是私有的,设置和获取仅限于源文件。
  • 一位 Swift 编译器工程师在 Twitter 上确认,这种行为看起来像是一个错误。
  • 没错,我目前正在尝试创建一个框架,并且我遇到了基类的设置器必须是内部的(这样只有该框架的其他类才能使用它)的情况。我还尝试将name 直接作为存储属性,但后来我无法覆盖getter(如果我没记错的话)。

标签: swift inheritance overriding getter-setter


【解决方案1】:

这对我有用:

public class MyBaseClass {
    private var _name: String = "Hi"
    public internal(set) var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
            super._name = newValue
        }
    }
}

MyDerivedClass().name

编辑

这段代码在操场上为我工作,将它放在 Sources -> SupportCode.swift 文件中

public class MyBaseClass {
private var _name: String = "Hi"
public internal(set) var name: String {
    get {
        return self._name
    }
    set {
        self._name = newValue
    }
}
public init() {

}

}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
           // do nothing
        }
    }
   public override init() {

    }
}

这有点麻烦,因为我得到了和你一样的警告,internal(set) 不能放在被覆盖的子类变量之前。这很可能是一个错误。而且我在作弊以确保派生类的设置器什么都不做。

internal(set)private(set) 更常见的用法是有这样的代码,与文档中的类似:

public class MyBaseClass {
    public private(set) var _name: String = "Hi"
    public var name: String {
        get {
            return self._name
        }
        set {
            self._name = newValue
        }
    }
    public init() {

    }

}

public class MyDerivedClass:MyBaseClass {
    override public var name: String {
        get {
            return "Derived - \(super.name)"
        }
        set {
           super._name = newValue
        }
    }
   public override init() {

    }
}

这里的 setter 可以直接用MyDerivedClass()._name 读取,但不能更改,例如这个MyDerivedClass()._name = "Fred" 会引发错误,但MyDerivedClass().name = "Fred" 可以。

【讨论】:

  • 这会公开setter吗?
【解决方案2】:

问题 1

MyBaseClass 无法编译因为:

  1. 它有一个存储的属性 (_name)
  2. 这个存储的属性是非可选的,所以它不能是 nil
  3. 没有初始化器来填充它

所以首先我们需要给 MyBaseClass 添加一个合适的初始化器

public class MyBaseClass {
    private var _name: String
    public internal(set) var name: String {
        get { return self._name }
        set { self._name = newValue }
    }
    init(name : String){
        _name = name
    }
}

问题 2

现在我们可以声明覆盖计算属性的MyDerivedClass

  1. 我们需要使用魔法关键字override
  2. 我们需要同时提供 setter 和 getter

代码如下:

public class MyDerivedClass: MyBaseClass {
    public override var name: String {
        get { return "Derived - \(super.name)" }
        set { super.name = newValue }
    }
}

测试

从我的游乐场:

let somethingWithAName = MyDerivedClass(name: "default name")
println(somethingWithAName.name) // > "Derived - default name"
somethingWithAName.name = "another name"
println(somethingWithAName.name) // > "Derived - another name"

【讨论】:

  • 将 internal(set) 放在计算变量之前表示可以公开检索但只能在内部设置。我认为 BPCorp 希望在被覆盖的属性内的子类中复制这些条件,但它似乎不可能,因为您不能重复使用 internal(set)。一个错误?意外的使用模式?
猜你喜欢
  • 2014-11-04
  • 2020-08-30
  • 2015-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 2011-03-11
相关资源
最近更新 更多