Swift Tips 029 - Making weak or lazy properties readonly

482 阅读2分钟

代码截图

代码出处: Swift Tips 029 by John Sundell

小笔记

这段代码在说什么

今天的这段代码为 Node 类设置了两个 readonly 的属性:parent 和 children,与其他 read only 属性不太一样的地方是:它们并没有显式的声明 getter 方法,而且看起来也不怎么像一个计算属性(因为只有计算属性才能 read only)。

通过为计算属性设置 get 和 set 方法,就可以实现计算属性的只读(只实现 get),可读可写(get 和 set),如果你想了解更多,可以阅读官方手册的属性章节。需要注意的是,这里要区分存储属性和计算属性!

简洁优雅的 private(set)

如果你问一个 Swift 开发者:如果想声明一个公开 getter,隐藏 setter 的属性,最简洁最优雅的方式是什么。

我想九成的开发者会说 ---- private(set)

但是你有没有好奇过这个“简洁优雅”的由来,如果不用 private(set) 的话怎么做呢?

实现一个相同的功能吧

怎么看 parentchildren 都像个存储属性,但它又做到了 read only,那么它到底是怎么实现只读的呢?

如果你没想到怎么做,来看看下面的代码吧,当然可行的解决方案有很多,下面只是其中一个而已!

class Node {
    private weak var _parent: Node?
    var parent: Node? {
        return _parent
    }

    private lazy var _children = [Node]()
    var children: [Node] {
        return _children
    }

    func add(child: Node) {
        _children.append(child)
        child._parent = self
    }
}

现在你能理解了么?

我们通过内置一个 private 访问级别的属性(_parent,_children)来持有真正的值,但向外只暴露一个与此关联的计算属性(parent, children),通过这种方式我们实现了与 private(set) 相同的效果。

再多说一点

很显然,private(set)让代码变得更加简洁和优雅了!但是如果我想改变 getter 方法的访问等级,又该怎么办呢?

如果你不理解访问等级,建议阅读官方手册里关于访问控制一节的内容

很简单,你只需要在 private(set) 前面加上对应的访问等级修饰符即可改变 getter 方法的访问等级了,例如下面的代码就将 parent 属性的 getter 方法变为了 public 级别。

    public private(set) weak var parent: Node?

说了这么多,今天的这个 tip 你喜欢么?