无需移除的通知Api-iOS

灵感来自新版KVO的api,绑定一个对象在当前监听通知的对象,然后在绑定对象dealloc的时候进行移除
不废话直接上代码
调用:

KCNotificationObserverProtocol//实现改协议,也可以给NSObject添加分类,但是那样感觉没有权限控制,所有用协议限制下
addNotificationObserver(forName: DemoVc.CLICK_BTN, object: nil, queue: OperationQueue.main) { [weak self](notification) in
            print("clickBtn")
        }
// 包装来自于NotificationCenter.addObserver(forName:object:queue:using:)观察者token
/// 当token deinit的时候,自动删除观察者。
public final class NotificationToken: NSObject {
    let notificationCenter: NotificationCenter
    let token: Any
    
    init(notificationCenter: NotificationCenter = .default, token: Any) {
        self.notificationCenter = notificationCenter
        self.token = token
    }
    deinit {
        notificationCenter.removeObserver(token)
    }
}

extension NotificationCenter {
    /// 封装NotificationCenter.addObserver(forName:object:queue:using:)
    /// 返回自定义的NotificationToken
    public func observe(forName name: NSNotification.Name,
                        object obj: Any?,
                        queue: OperationQueue?,
                        using block: @escaping (Notification) -> ()) -> NotificationToken {
        let token = addObserver(forName: name, object: obj, queue: queue, using: block)
        return NotificationToken(notificationCenter: self, token: token)
    }
}


private var tokensKey = "KCNotificationTokensKey"
public protocol KCNotificationObserverProtocol: NSObjectProtocol {}

extension KCNotificationObserverProtocol {
    /// 封装NotificationCenter.addObserver(forName:object:queue:using:)
    /// 动态给当前对象增加观察者token字典 [NSNotification.Name: NotificationToken]
    public func addNotificationObserver(forName name: NSNotification.Name,
                                        object obj: Any?,
                                        queue: OperationQueue?,
                                        using block: @escaping (Notification) -> ()) {
        var tokens = getTokens()
        let token = NotificationCenter.default.observe(forName: name, object: nil, queue: queue, using: block)
        tokens[name] = token
        setTokens(tokens)
    }
    
    /// 删除某个观察
    /// - Parameter name: NSNotification.Name
    public func removeNotificationObserver(forName name: NSNotification.Name) {
        var tokens = getTokens()
        tokens.removeValue(forKey: name)
        setTokens(tokens)
    }
        
    private func getTokens() -> [NSNotification.Name: NotificationToken] {
        synchronized(self) {
            if let observers = objc_getAssociatedObject(self, &tokensKey) as? [NSNotification.Name: NotificationToken] {
                return observers
            }
            return [NSNotification.Name: NotificationToken]()
        }
    }
    
    private func setTokens(_ tokens: [NSNotification.Name: NotificationToken]) {
        synchronized(self) {
            objc_setAssociatedObject(self, &tokensKey, tokens, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

public func synchronized(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

demo请看下面
https://github.com/riceForChina/NotificationCenter-Tool.git

你可能感兴趣的:(无需移除的通知Api-iOS)