1

私はプロトコルを持っています

protocol Example: class {
    var value: Bool { get set }
    func foo()
    func bar()
}

そして拡張子:

extension Example {

//    var value: Bool { // Error: Extensions must not contain stored properties
//        didSet {
//            switch value {
//            case true:
//                foo()
//            case false:
//                bar()
//            }
//        }
//    }

    func foo() {
        // logic...
    }
    func bar() {
        // logic...
    }
}
  • valueがのとき、呼ばれtrueたいfoo()
  • valueがのとき、呼ばれfalseたいbar()

didSet{ }ただし、準拠するすべてのクラスにロジックを冗長に実装したくありません。Example

しかし、didSet{ }拡張機能にロジックを追加しようとすると、Xcode は「拡張機能に格納されたプロパティを含めることはできません」と表示します。

すべての準拠クラスにコピー/貼り付けする必要なく、デフォルトのプロパティ監視ロジックを追加するためのベスト プラクティスは何ですか?

目標:

のサブクラスをUIViewプロトコルに準拠させたいExpandable。私のプロトコルの要件は、、、isExpanded: Boolおよびexpand()ですcollapseisExpanded = trueを呼び出してexpand()isExpanded = false呼び出したいcollapse()(設定の動作とよく似ていますisHidden)。しかし、UIView のすべてのサブクラスについて、ロジックを書き直す必要はありません。Expandableクラスを に準拠させて、すぐに設定に飛び込みたいと思いますisExpanded

4

2 に答える 2

-1

あなたが説明していることにオブザーバーは必要ありません。状態用のストレージが必要なだけです。これが NSObject であることはわかっているので、ObjC ランタイムでそれを行うことができます。

// Since we know it's a UIView, we can use the ObjC runtime to store stuff on it
private var expandedProperty = 0

// In Xcode 10b1, you can make Expandable require this, but it's probably
// nicer to still allow non-UIViews to conform.
extension Expandable where Self: UIView {
    // We'll need a primitive form to prevent infinite loops. It'd be nice to make this private, but
    // then it's not possible to access it in custom versions of expand()
    var _isExpanded: Bool {
        get {
            // If it's not know, default to expanded
            return objc_getAssociatedObject(self, &expandedProperty) as? Bool ?? true
        }
        set {
            objc_setAssociatedObject(self, &expandedProperty, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
    var isExpanded: Bool {
        get {
            return _isExpanded
        }
        set {
            _isExpanded = newValue
            if newValue { expand() } else { collapse() }
        }
    }
    func expand() {
        _isExpanded = true  // Bypassing the infinite loop
        print("expand")

    }
    func collapse() {
        _isExpanded = false
        print("collapse")
    }
}

これが NSObject であることを知らなかった場合は、ObjectIdentifier -> Bool をマップするグローバル (プライベート) 辞書を使用して同じことを取得できます。わずかな量のメモリがリークするだけです (折りたたむビューごとに最大 16 バイト)。

そうは言っても、私はこのようにはしません。同じことを行う方法が 2 つあると、すべてがはるかに複雑になります。私は同じisExpandedように設定可能にするかisExpanded、読み取り専用と aexpandcollapse. その後、余分なものは必要ありません_isExpanded

于 2018-06-12T16:35:44.480 に答える