// // Observers.swift // TUICallKit // // Created by vincepzhang on 2023/4/3. // import Foundation class Observer {} public class Observable { // MARK: - Callback fileprivate class Callback { fileprivate weak var observer: AnyObject? fileprivate let options: [ObservableOptions] fileprivate let closure: (Type, ObservableOptions) -> Void fileprivate init( observer: AnyObject, options: [ObservableOptions], closure: @escaping (Type, ObservableOptions) -> Void) { self.observer = observer self.options = options self.closure = closure } } // MARK: - Properties Use Swift's didSet feature to call back the value to the callback public var value: Type { didSet { removeNilObserverCallbacks() notifyCallbacks(value: oldValue, option: .old) notifyCallbacks(value: value, option: .new) } } private func removeNilObserverCallbacks() { callbacks = callbacks.filter { $0.observer != nil } } // MARK: Callback to callback to implement closure callback private func notifyCallbacks(value: Type, option: ObservableOptions) { let callbacksToNotify = callbacks.filter { $0.options.contains(option) } callbacksToNotify.forEach { $0.closure(value, option) } } // MARK: - Object Lifecycle public init(_ value: Type) { self.value = value } // MARK: - Managing Observers private var callbacks: [Callback] = [] public func addObserver( _ observer: AnyObject, removeIfExists: Bool = true, options: [ObservableOptions] = [.new], closure: @escaping (Type, ObservableOptions) -> Void) { if removeIfExists { removeObserver(observer) } let callback = Callback(observer: observer, options: options, closure: closure) callbacks.append(callback) if options.contains(.initial) { closure(value, .initial) } } public func removeObserver(_ observer: AnyObject) { callbacks = callbacks.filter { $0.observer !== observer } } } // MARK: - ObservableOptions public struct ObservableOptions: OptionSet { public static let initial = ObservableOptions(rawValue: 1 << 0) public static let old = ObservableOptions(rawValue: 1 << 1) public static let new = ObservableOptions(rawValue: 1 << 2) public var rawValue: Int public init(rawValue: Int) { self.rawValue = rawValue } }