Swift KVO - 观察枚举属性

 mobiledu2502894453 发布于 2022-12-07 18:30

我正在组装一个类,它有一个由枚举定义的状态,以及一个只读属性"state",它返回实例的当前状态.我希望使用KVO技术来观察状态的变化,但这似乎不可能:

dynamic var state:ItemState // Generates compile-time error: Property cannot be marked dynamic because its type cannot be represented in Objective-C

我想我可以将每个状态表示为Int或String等,但是有一个简单的替代解决方法可以保留enum否则会提供的类型安全性吗?

文斯.

2 个回答
  • 也许这仅适用于swift 2+,但您可以直接观察枚举属性,而无需引用其rawValue.但它确实有一些限制.

      NSObject(直接或间接)扩展包含类

      用枚举标记枚举 @objc

      从中扩展枚举 Int

      将该属性声明为dynamic.

    class SomeModel : NSObject {                          // (1) extend from NSObject
        @objc                                             // (2) mark enum with @objc
        enum ItemState : Int, CustomStringConvertible {   // (3) extend enum from Int
            case Ready, Set, Go
    
            // implementing CustomStringConvertible for example output
            var description : String {
                switch self {
                case .Ready: return "Ready"
                case .Set: return "Set"
                case .Go: return "Go"
                }
            }
        }
    
        dynamic var state = ItemState.Ready               // (4) declare property as dynamic
    }
    

    别处:

    class EnumObserverExample : NSObject {
        private let _model : SomeModel
    
        init(model:SomeModel) {
            _model = model
            super.init()
            _model.addObserver(self, forKeyPath:"state", options: NSKeyValueObservingOptions.Initial, context: nil)
        }
        deinit {
            _model.removeObserver(self, forKeyPath:"state", context: nil)
        }
    
        override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
            if "state" == keyPath {
                print("Observed state change to \(_model.state)")
            }
        }
    }
    
    let model = SomeModel()
    let observer = EnumObserverExample(model:model)
    model.state = .Set
    model.state = .Go
    

    输出:

    Observed state change to Ready    (because .Initial was specified)
    Observed state change to Set
    Observed state change to Go
    

    2022-12-11 02:05 回答
  • 我刚才遇到了同样的问题.最后,我使用了枚举状态,并添加了一个额外的'raw'属性,该属性由主状态属性上的属性观察者设置.

    您可以KVO'原始'属性,但在更改时引用真实的枚举属性.

    这显然有点像黑客,但对我来说,这比完全放弃枚举并失去所有好处要好.

    例如.

    class Model : NSObject {
    
        enum AnEnumType : String {
            case STATE_A = "A"
            case STATE_B = "B"
        }
    
        dynamic private(set) var enumTypeStateRaw : String?
    
        var enumTypeState : AnEnumType? {
            didSet {
                enumTypeStateRaw = enumTypeState?.rawValue
            }
        }
    }
    

    额外:

    如果您正在编写正在Swift中进行观察的类,这里有一个方便的实用程序类来消除一些痛苦.好处是:

      您的观察者不需要继承NSObject.

      观察回调代码作为闭包而不是必须实现observeValueForKeyPath:BlahBlah ...

      没有必要确保你删除Observer,它会为你照顾.

    调用实用程序类KVOObserver,示例用法是:

    class ExampleObserver {
    
        let model : Model
        private var modelStateKvoObserver : KVOObserver?
    
        init(model : Model) {
    
            self.model = model
    
            modelStateKvoObserver = KVOObserver.observe(model, keyPath: "enumTypeStateRaw") { [unowned self] in
                println("new state = \(self.model.enumTypeState)")
            }
        }
    }
    

    请注意[unowned self]捕获列表中的参考周期.

    这是KVOObserver......

    class KVOObserver: NSObject {
    
        private let callback: ()->Void
        private let observee: NSObject
        private let keyPath: String
    
        private init(observee: NSObject, keyPath : String, callback: ()->Void) {
            self.callback = callback
            self.observee = observee
            self.keyPath = keyPath;
        }
    
        deinit {
            println("KVOObserver deinit")
            observee.removeObserver(self, forKeyPath: keyPath)
        }
    
        override func observeValueForKeyPath(keyPath: String,
            ofObject object: AnyObject,
            change: [NSObject : AnyObject],
            context: UnsafeMutablePointer<()>) {
                println("KVOObserver: observeValueForKey: \(keyPath), \(object)")
                self.callback()
        }
    
        class func observe(object: NSObject, keyPath : String, callback: ()->Void) -> KVOObserver {
            let kvoObserver = KVOObserver(observee: object, keyPath: keyPath, callback: callback)
            object.addObserver(kvoObserver, forKeyPath: keyPath, options: NSKeyValueObservingOptions.New | NSKeyValueObservingOptions.Initial, context: nil)
            return kvoObserver
        }
    }
    

    2022-12-11 02:06 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有