KVO
原理模拟
实现观察者模式,hook setter方法,调用setter的时候通知观察者
(属性需要标记为dynamic)
class KVO: NSObject {
var observers: [String: [KVO]] = [:]
func addObserver(_ observer: KVO, forKey key: String) {
observers[key, default: []].append(observer)
let setterSelector = Selector("set\(key.capitalized):")
let oldImp = {
let method = class_getInstanceMethod(Self.self, setterSelector)!
let imp = method_getImplementation(method)
return unsafeBitCast(imp, to: (@convention(c) (Any, Selector, Any) -> Void).self)
}()
let newSetter: @convention(block) (Any, Any) -> Void = { [weak self] obj, newValue in
oldImp(obj, setterSelector, newValue)
self?.observers[key]?.forEach { observer in
observer.observeValue(forKey: key, of: self)
}
}
class_replaceMethod(Self.self, setterSelector, imp_implementationWithBlock(newSetter), nil)
}
func observeValue(forKey key: String, of object: Any?) {}
}
Swift解决方案
语言层面属性观察器
struct A {
var a = 0 {
willSet {
print("will be", newValue)
}
didSet {
print("was", oldValue)
}
}
}
通知原理模拟
观察者模式的变体,不存储不关心属性,仅添加观察者,向观察者发送通知
class NotificationCenter: @unchecked Sendable {
var observers: [String: [(String) -> Void]] = [:]
static let `default` = NotificationCenter()
func addObserver(forName name: String, using block: @escaping (String) -> Void) {
observers[name, default: []].append(block)
}
func post(name: String) {
observers[name]?.forEach { block in
block(name)
}
}
}