【问题标题】:Add property observer to global variable inside class in Swift将属性观察器添加到 Swift 中的类内的全局变量
【发布时间】:2017-09-10 12:36:21
【问题描述】:

我在全局范围内声明了一个变量globalVariable,它可能随时更改。

globalVariable 发生变化时,我的应用程序中的不同ViewControllers 需要做出不同的反应。

因此,最好在每个ViewController 中添加一个属性观察器,以便在globalVariable 更改时执行所需的代码。

我似乎无法通过overrideextension 实现它这里怎么走?

【问题讨论】:

    标签: ios swift properties global-variables


    【解决方案1】:

    如果您的目标是简单地知道您的全局变量何时更改,您可以让它在更改时发布通知:

    extension NSNotification.Name {
        static let globalVariableChanged = NSNotification.Name(Bundle.main.bundleIdentifier! + ".globalVariable")
    }
    
    var globalVariable: Int = 0 {
        didSet {
            NotificationCenter.default.post(name: .globalVariableChanged, object: nil)
        }
    }
    

    然后任何对象都可以为该通知添加观察者:

    class ViewController: UIViewController {
    
        private var observer: NSObjectProtocol!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // add observer; make sure any `self` references are `weak` or `unowned`; obviously, if you don't reference `self`, that's not necessary
    
            observer = NotificationCenter.default.addObserver(forName: .globalVariableChanged, object: nil, queue: .main) { [weak self] notification in
                // do something with globalVariable here
            }
        }
    
        deinit {
            // remember to remove it when this object is deallocated
    
            NotificationCenter.default.removeObserver(observer)
        }
    
    }
    

    注意,如果 (a) 全局变量是引用类型,即 class,则此 didSet 机制将不会检测到更改; (b) 它只是改变全局变量引用的对象,而不是用新实例替换它。要识别这种情况,您需要使用 KVO 或其他机制来检测突变。

    【讨论】:

      【解决方案2】:

      全局变量只能有一个 didSet{} 函数,并且它必须属于变量本身。您可以做的是让变量的 didSet{} 函数调用其他对象的函数列表。

      您可以为此使用通知,也可以构建自己的机制。

      这是一个如何创建自己的机制的示例:

      (请注意,这是非常通用的,适用于任何变量类型或单例实例)

      // Container for an observer's function reference
      // - will be used to call the observer's code when the variable is set
      // - Separates the object reference from the function reference
      //   to avoid strong retention cycles.
      struct GlobalDidSet<T>
      {
         weak var observer:AnyObject?
         var didSetFunction:(AnyObject)->(T)->()
         init(_ observer:AnyObject, didSet function:@escaping (AnyObject)->(T)->())
         {
            self.observer  = observer
            didSetFunction = function
         }
      }
      
      // Container for a list of observers to be notified
      // - maintains the list of observers
      // - automatically clears entries that non longer have a valid object
      // - calls all observers when variable changes
      // - erases type of observer to allow generic use of GlobalDidSet<>
      struct GlobalDidSets<T>
      {
         var observers : [GlobalDidSet<T>] = []
         mutating func register<O:AnyObject>(_ observer:O, didSet function:@escaping (O)->(T)->())
         {
            let observer = GlobalDidSet<T>(observer)
            { (object:AnyObject) in function(object as! O) }
            observers.append(observer)  
         }
      
         mutating func notifyDidSet(_ oldValue:T)
         {
            observers = observers.filter{$0.observer != nil}
            observers.forEach{ $0.didSetFunction($0.observer!)(oldValue) }
         }
      }
      

      ...

      // To use this, you will need a second variable to manage the list of observers
      // and your global variable's didSet{} must use that observer list
      // to perform the multiple function calls
      //
      var globalVariableDidSets = GlobalDidSets<String>()
      var globalVariable : String = "Initial Value"
      {
         didSet { globalVariableDidSets.notifyDidSet(oldValue) }
      }
      
      // In your view controllers (or any other class), you need to setup the 
      // reaction to the global variable changes by registering to the observer list
      //
      class MyVC:UIViewController
      {
          override func viewDidLoad()
          {
            globalVariableDidSets.register(self){ $0.handleVariableChange }  
            // ...
          }
      
          func handleVariableChange(_ oldValue:String)
          {
            //...
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-01
        • 2019-02-16
        • 2016-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-10
        • 1970-01-01
        相关资源
        最近更新 更多