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: Boolexpand()collapse。我想isExpanded = 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 个字节)。

也就是说,我不会这样做。有两种方法来做同样的事情会使一切变得更加复杂。我要么是可设置isExpanded的,要么isExpanded是只读的和一个expandcollapse。那么你不需要额外的_isExpanded.

于 2018-06-12T16:35:44.480 回答
-3

你必须明确地实现getter、setter:

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

extension Example {
   var value: Bool {
       get { return value }

       set(newValue) {
           value = newValue
           value ? foo() : bar()
        }
    }


   func foo() {
       print("foo")
   }

   func bar() {
       print("bar")
   }
}
于 2018-06-11T02:18:40.527 回答