在一个类中观察静态变量的值?

8

我有一个类,其中包含一个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
    }
}
4个回答

8

目前,Swift不能拥有可观察的类属性。(事实上,静态属性只是带有其命名空间限制在类中的全局变量。)

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


谢谢,我会尝试单例模式。 - MJQZ1347

5

我使用@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" {
        // ...
    }
}

根据此处的错误信息:https://dev59.com/EVYO5IYBdhLWcg3wEdhO,添加了`@objc`。 - pkamb

2

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

发生的情况是因为它继承自NSObject,Swift会尝试为其生成getter和setter。因为您正在使用Swift创建它,使用@nonobjc属性解决了这个问题。

编辑:

我认为你不能通过KVO观察静态变量,因为它的工作方式如下所示:

以下是来自Apple KVO指南的链接和代码段:

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

也许,您可以像这样声明online:

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

如果你决定使用它,这个问题可能会指向正确的方向 - 它将涉及深入了解KVO工作原理:在Objective C中是否可以设置KVO通知来监视静态变量?

@MJQZ1347 更新的答案 - TheBrownCoder
我也想到了NSNotification,但是有点惊讶没有其他方法来观察静态变量。但我认为那就是解决问题的方法。另外:为什么不使用didSet而不是set呢? - MJQZ1347
@MJQZ1347 哎呀,我的错。我是指 didSet。你说得对,这确实有点奇怪,因为它是一个非常有用的功能。也许将来会加入! - TheBrownCoder

0
我建议使用属性包装器,我尝试了下面的示例,对我来说完美地工作了:
    @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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接