[英]Add property observer to global variable inside class in Swift
I have a variable globalVariable
declared at global scope that may change at any time. 我在全局范围内声明了一个变量globalVariable
,该变量可能随时更改。
Different ViewControllers
in my app need to react differently, when globalVariable
changes. 当globalVariable
更改时,我的应用程序中的不同ViewControllers
需要做出不同的反应。
Thus it would be desirable to add a property observer in each ViewController
that execute the needed code when globalVariable
changes. 因此,需要在globalVariable
更改时在执行所需代码的每个ViewController
中添加属性观察器。
I cannot seem to achieve it with override
or extension
. 我似乎无法通过override
或extension
来实现它 。 What is the way to go here? 去这里的路是什么?
If your goal is to simply know when your global variable changed, you could have it post a notification upon change: 如果您的目标是仅知道全局变量何时更改,则可以让它在更改后发布通知:
extension NSNotification.Name {
static let globalVariableChanged = NSNotification.Name(Bundle.main.bundleIdentifier! + ".globalVariable")
}
var globalVariable: Int = 0 {
didSet {
NotificationCenter.default.post(name: .globalVariableChanged, object: nil)
}
}
Then any object can add an observer for that notification: 然后,任何对象都可以为该通知添加观察者:
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)
}
}
Note, this didSet
mechanism will not detect changes if (a) the global variable is a reference type, ie a class
; 注意,如果(a)全局变量是引用类型,即class
,则didSet
机制将不会检测到更改。 and (b) it merely mutates the object that the global variable references rather than replacing it with a new instance. (b)仅更改全局变量引用的对象,而不用新实例替换它。 To identify that scenario, you need to use KVO or other mechanism to detect mutation. 要确定该情况,您需要使用KVO或其他机制来检测突变。
There can be only one didSet{} function for your global variable and it must belong to the variable itself. 全局变量只能有一个didSet {}函数,它必须属于变量本身。 What you can do is make the variable's didSet{} function call a list of functions from other objects. 您可以做的是使变量的didSet {}函数从其他对象调用函数列表。
You could use notifications for this or you could build your own mechanism. 您可以为此使用通知,也可以构建自己的机制。
Here's an example of how you could create your own mechanism: 这是如何创建自己的机制的示例:
(note that this is pretty generic and could work for any variable types or singleton instance) (请注意,这是非常通用的,可以用于任何变量类型或单例实例)
// 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)
{
//...
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.