2

我正在创建 UIStackView 的子类,并且我希望间距是静态且不可覆盖的。我认为这可以简单地通过覆盖spacing属性来完成:

class MyStackView: UIStackView {
    override var spacing: CGFloat {
        get { return 8.0 }
        set {}
    }
}

但是,这不起作用。getter 永远不会被调用,也不会显示间距。我为此找到的唯一解决方案是以下代码:

class MyStackView: UIStackView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        super.spacing = 8.0
    }

    override var spacing: CGFloat {
        get { return 8.0 }
        set {}
    }
}

实际上,我返回什么并不重要get,反正它从来没有被任何东西调用过。

任何人都可以解释这种行为] r 以及如何避免它?

4

1 回答 1

2

在我看来,这里发生了什么。你想实现两件事:

  1. 默认情况下,间距MyStackView应为8.0
  2. 该间距值不应从外部更改

要实现第一件事,您需要覆盖初始化程序并在其中设置默认值。

class MyStackView: UIStackView {

    private let defaultSpacing: CGFloat = 8.0

    override init(frame: CGRect) {
        super.init(frame: frame)
        super.spacing = defaultSpacing
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        super.spacing = defaultSpacing
    }

}

对于第二件事,您需要覆盖getterand setterofspacing以控制来自外部的任何更改。

class MyStackView: UIStackView {

    ...

    override var spacing: CGFloat {
        get { return defaultSpacing }
        set { print("MyStackView spacing it always \(defaultSpacing)") }
    }

}

为什么你不能简单地覆盖一个变量并得到相同的结果?

UIStackView.spacing属性是计算出来的,它不是一个容器。我们可能不关心原始getter作品的效果,因为我们知道我们的间距总是相同的。我们知道它的值,并且总是可以在覆盖的 getter 处返回它。

但我们也不知道原创setter作品是如何工作的,以及它做了哪些改变UIStackView。从那以后,我们不能简单地覆盖getter. 我们必须显式调用super.spacing = defaultValue一次,以触发原始setter并设置所需的值。

于 2018-09-09T10:43:21.853 回答