设置属性P

时间:2019-03-01 15:57:59

标签: swift setter private-members

我有一个属性和一个方法:

class C {
    var myProperty = ""
    func myFunc() {

    }
}

我希望有一个规则,当您设置myProperty时,您必须 然后继续呼叫myFunc。当然,我可以有一个 mental 规则,要求这样做,但是精神契约根本不是契约。我想通过类的API 执行该合同。

注意,所有这些纯粹是关于内部 C的内容。myPropertymyFunc都可以是私有的 outside C;这不会影响问题。)

很明显,我们可以使用二传手观察者来做到这一点:

class C1 {
    var myProperty = "" {
        didSet {
            self.myFunc()
        }
    }
    func myFunc() {

    }
}

但是,对于该解决方案,我有些不满意:它取决于构成隐藏副作用的原因。我要知道,说self.myProperty = "..."还会触发对myFunc的呼叫。我不喜欢那种隐藏的副作用;它使我的代码更难以理解,并且违反了我的一项重要编程原则,即说出你的意思。

我的意思是什么?我的意思是这样的:

self.setMyPropertyAndCallMyFunc("...")

我喜欢这样,因为它可以准确地告诉我每次调用在我的代码中发生的情况。所以我们可以这样写:

class C2 {
    var myProperty = ""
    func myFunc() {

    }
    func setMyPropertyAndCallMyFunc(_ s:String) {
        self.myProperty = s
        self.myFunc()
    }
}

但是 存在一个问题,即现在可以在不调用myProperty的情况下设置myFunc,从而打破了我们首先要执行的规则地点!我发现执行该规则的唯一方法是拥有另一个类,该类可以保护隐私。例如:

class C3 {
    class Inner {
        private(set) var myProperty = ""
        private func myFunc() {

        }
        func setMyPropertyAndCallMyFunc(_ s:String) {
            self.myProperty = s
            self.myFunc()
        }
    }
    let inner = Inner()
}

这实际上是我正在做的事情,但是拥有第二类只是为了执行这些隐私和命名规则似乎有点坚果。我的问题是:还有另一种方法吗?

1 个答案:

答案 0 :(得分:1)

是的,尽管我不知道它是否真的更好。您可以将myProperty隐藏在闭包内部,而不是隐藏在类/结构内部。例如:

class C {
    public var myProperty: String { return _myPropertyGetter() }
    public func setMyPropertyAndCallMyFunc(value: String) {
        _myPropertySetter(self, value)
    }

    func myFunc() {
        print("myFunc")
    }

    private let (_myPropertyGetter, _myPropertySetter): (() -> String, (C, String) -> ()) = {
        var property = ""
        return ({ property }, { property = $1; $0.myFunc() })
    }()
}

let c = C()
c.myProperty
c.setMyPropertyAndCallMyFunc(value: "x")
c.myProperty

这里有很多复杂性,例如将self传递给_setMyPropertyAndCallMyFunc来允许myFunc生活在闭包之外,也许可以省去其中的一部分。但是基本思想是生成两个函数,这是唯一可以访问属性存储的函数,从而使其在不创建内部类的情况下成为“超级私有”。

如果您不需要公开myFunc()(并且从您的Inner示例中,我认为您不需要公开),则可以更简单一些,这可能比Inner更好。

class C {
    public var myProperty: String { return _myPropertyGetter() }
    public func setMyPropertyAndCallMyFunc(value: String) { _myPropertySetter(value) }

    private let (_myPropertyGetter, _myPropertySetter): (() -> String, (String) -> ()) = {
        var property = ""
        func myFunc() {
            print("myFunc")
        }
        return ({ property }, { property = $0; myFunc() })
    }()
}