【问题标题】:Observing a value of a static var in a class?观察类中静态变量的值?
【发布时间】:2016-11-09 03:32:57
【问题描述】:

我有一个带有static var 的类,其中存储了当前的在线连接状态。我想通过其他类观察ConnectionManager.online的值。我想用 KVO 来做这件事,但是将 static 变量声明为 dynamic 会导致错误:

class ConnectionManager: NSObject {
    dynamic static var online = false
    // adding 'dynamic' declaration causes error:
    // "A declaration cannot be both 'final' and 'dynamic'
}

这样做最优雅的方式是什么?

更新。这是我的 KVO 部分代码:

override func viewDidLoad() {
    super.viewDidLoad()

    ConnectionManager.addObserver(
        self,
        forKeyPath: "online",
        options: NSKeyValueObservingOptions(),
        context: nil
    )
}

override func observeValueForKeyPath(keyPath: String?, 
                                     ofObject object: AnyObject?, 
                                     change: [String : AnyObject]?, 
                                     context: UnsafeMutablePointer<Void>) {
    if keyPath == "online" {
        print("online status changed to: \(ConnectionManager.online)")
        // doesn't get printed on value changes
    }
}

【问题讨论】:

    标签: ios swift cocoa-touch key-value-observing class-variables


    【解决方案1】:

    就目前而言,Swift 不能具有可观察的类属性。 (实际上,静态属性只是全局变量,其命名空间被限制在一个类中。)

    如果您想使用 KVO,请创建一个具有 online 属性的共享实例(单例类)并将观察者添加到该实例。

    【讨论】:

    • 谢谢,将尝试单例模式。
    【解决方案2】:

    我用@OOper 建议的singleton 模式解决了这个问题。

    class ConnectionManager: NSObject {
        static let sharedInstance = ConnectionManager()
        private override init() {} // This prevents others from using the default '()' initializer for this class.
        @objc dynamic var online = false
    }
    

    然后:

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.tableFooterView = UIView()
    
        ConnectionManager.sharedInstance.addObserver(self,
                             forKeyPath: "online",
                             options: [.new, .initial],
                             context: nil)
    }
    
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if object is ConnectionManager && keyPath == "online" {
            // ...
        }
    }
    

    【讨论】:

    【解决方案3】:

    尝试将dynamic static var online = false 替换为@nonobjc static var online = false

    因为它继承自 NSObject,所以 Swift 试图为它生成 getter 和 setter。因为您是在 swift 中创建它,所以使用 @nonobjc 属性可以解决问题。

    编辑:

    我不相信你可以通过 KVO 观察静态变量,因为它是如何工作的

    这是来自Apple's Guide on KVO的链接和sn-p

    与使用 NSNotificationCenter 的通知不同,没有 为所有观察者提供更改通知的中心对象。 相反,通知直接发送到观察对象 进行了更改。

    也许,您可以在线声明,而不是使用 KVO:

    static var online = false {
        didSet{
            //code to post notification through regular notification center
        }
    }
    

    如果您打算使用它,这个问题可能会为您指明正确的方向——它将涉及更深入地了解 KVO 的工作原理:Is it possible to set up KVO notifications for static variables in objective C?

    【讨论】:

    • @MJQZ1347 更新答案
    • 我也想到了NSNotification,但我有点惊讶没有其他方法可以观察静态变量。但我认为这是要走的路。另外:为什么不使用didSet 而不是set
    • @MJQZ1347 哎呀,我的错。我的意思是didSet。不过,您是对的,这有点奇怪,因为它是一个非常有用的功能。也许它会在未来出现!
    【解决方案4】:

    我建议使用属性包装器,我尝试了下面的示例,并且非常适合我:

        @propertyWrapper
        struct StaticObserver<T> {
            private var value:T
            init(value:T) {
                self.value = value
            }
            var wrappedValue: T {
            get {
                // Do your thing
                return self.value
            }
            set {
                // Do your thing before set 
                self.value = newValue
                // Do your thing after set
            }
        }
    
        @StaticObserver(value: false)
        dynamic static var online:Bool
    

    【讨论】:

      猜你喜欢
      • 2017-03-01
      • 2015-01-10
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多