[英]Add property observer to global variable inside class in Swift
我在全局范圍內聲明了一個變量globalVariable
,該變量可能隨時更改。
當globalVariable
更改時,我的應用程序中的不同ViewControllers
需要做出不同的反應。
因此,需要在globalVariable
更改時在執行所需代碼的每個ViewController
中添加屬性觀察器。
我似乎無法通過override
或extension
來實現它 。 去這里的路是什么?
如果您的目標是僅知道全局變量何時更改,則可以讓它在更改后發布通知:
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或其他機制來檢測突變。
全局變量只能有一個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)
{
//...
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.