iOS开发中NSNotification的便利使用

Posted JackLee18

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发中NSNotification的便利使用相关的知识,希望对你有一定的参考价值。

   NSNotification的使用有几个痛点:1)无法自动释放监听;2)重复添加监听没有提示;3)使用不够便利。最近在推动项目中使用swift,将原来的OC代码写了一个swift版本分享给大家。

实现原理

OC版本主要通过NSObject的分类,动态绑定一个数组,每次添加通知的监听,都会创建一个proxy对象,将这个proxy对象添加到刚才动态添加的数组中。这个proxy是真正的通知的监听者。并且响应处理通知的block,释放的时候会移除监听。能够实现proxy对象释放时,自动移除监听。一个对象被释放时,动态绑定的proxy的数组也会被释放,数组里面的proxy元素也会被释放。这样监听就被自动移除了。

OC版本代码如下:

/**
 监听通知事件。对通知扩展封装,避免循环引用。

 @param name 通知名称
 @param block 通知事件处理
 */
- (void)jk_observeNotificationForName:(NSString *)name
                           usingBlock:(void(^)(NSNotification *notification))block;

/// 监听一组通知事件
/// @param names 通知名称数组
/// @param block 通知事件处理
- (void)jk_observeNotificationForNames:(NSArray<NSString *> *)names
                            usingBlock:(void(^)(NSNotification *notification))block;

/// 发送通知
/// @param name 通知的名字
- (void)jk_postNotification:(NSString *)name;

/// 发送通知
/// @param name 通知的名字
/// @param object object
/// @param userInfo userInfo
- (void)jk_postNotification:(NSString *)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo;
/**
 移除通知的监听

 @param name 通知名称
 */
- (void)removeNotification:(NSString *)name;

swift版本代码如下:

swift版本通过创建协议,并为协议添加默认实现,来达到OC版本分类的效果。

//
//  JKFastNotificationProtocol.swift
//  JKNoticationHelper_Swift
//
//  Created by JackLee on 2021/9/8.
//

import Foundation
//提供简便使用,不会自动移除通知的监听
public protocol JKFastNotificationProtocol {
    
    /// 添加通知的监听
    /// - Parameters:
    ///   - name: 通知的名字
    ///   - block: 处理通知的回调
    func jk_observeNotificaion(name:String, block:@escaping ((_ notification:Notification) -> Void)) ->Void
    
    /// 添加一组通知的监听
    /// - Parameters:
    ///   - names: 通知的名字组成的数组
    ///   - block: 处理通知的回调
    func jk_observeNotificaions(names:Array<String>,block:@escaping ((_ notification:Notification) -> Void)) ->Void
    
    /// 移除通知的监听
    /// - Parameter name: 通知的名字
    func jk_removeObserveNotification(for name:String) ->Void
    
    /// 发送通知
    /// - Parameter notificationName: 通知名字
    func jk_postNotification(notificationName:String) ->Void
    
    /// 发送通知
    /// - Parameters:
    ///   - notificationName: 通知名字
    ///   - object: 发送的对象
    ///   - userInfo: 用户信息
    func jk_postNotification(notificationName:String, object:Any?, userInfo:[AnyHashable : Any]?) ->Void
    
    
    var notificationProxyList: [JKFastNotificationProxy] {get set}
}

private struct JKFastNotificationProtocolAssociatedKey {
    static var identifier: String = "notificationProxyList_identifier"
}

public extension JKFastNotificationProtocol {
    
    var notificationProxyList: [JKFastNotificationProxy] {
        get{ objc_getAssociatedObject(self, &JKFastNotificationProtocolAssociatedKey.identifier) as? [JKFastNotificationProxy] ?? [] }
        set { objc_setAssociatedObject(self, &JKFastNotificationProtocolAssociatedKey.identifier, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
    }
    
     func jk_observeNotificaion(name:String, block:@escaping ((_ notification:Notification) -> Void)) ->Void {
        jk_observeNotificaions(names: [name], block: block)
    }
    
     func jk_observeNotificaions(names:Array<String>,block:@escaping ((_ notification:Notification) -> Void)) ->Void {
        var tmpSelf = self
        
        let proxyArr:[JKFastNotificationProxy] = names.compactMap {
            let name:String = $0
            let observered:Bool = tmpSelf.notificationProxyList.contains { proxy in
                return proxy.notificationName == name
            }
            if observered == false {
               return JKFastNotificationProxy(name: name, block: block)
            } else {
                #if DEBUG
                assert(false, "duplicated add observer of the same name!")
                #endif
                return nil
            }
        }
        tmpSelf.notificationProxyList += proxyArr
    }
    
     func jk_removeObserveNotification(for name:String) ->Void {
        var tmpSelf = self
        tmpSelf.notificationProxyList.removeAll { $0.notificationName == name}
    }
    
    func jk_postNotification(notificationName:String) ->Void {
        jk_postNotification(notificationName: notificationName, object: nil, userInfo: nil)
    }
    
    func jk_postNotification(notificationName:String, object:Any?, userInfo:[AnyHashable : Any]?) ->Void {
        NotificationCenter.default.post(name: Notification.Name.init(notificationName), object: object, userInfo: userInfo)
    }
}

swift版本使用示例:

import UIKit
import JKNoticationHelper_Swift
class ViewController: UIViewController,JKFastNotificationProtocol {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let button:UIButton = UIButton.init(frame: CGRect.init(x: 0, y: 0, width: 60, height: 60))
        button.backgroundColor = .red
        self.view.addSubview(button)
        button.center = self.view.center
        button.addTarget(self, action: #selector(buttonClicked), for:.touchUpInside)
        jk_observeNotificaion(name: "aaaaa") { notification in
            print("hahah")
        }
        
    }
    
    @objc func buttonClicked() ->Void {
       jk_postNotification(notificationName: "aaaaa")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

通过pod集成如下:

OC:

pod 'JKNoticationHelper'

swift:

pod 'JKNoticationHelper_Swift'

源码下载地址:https://github.com/xindizhiyin2014/JKNoticationHelper.git

以上是关于iOS开发中NSNotification的便利使用的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发中NSNotification的便利使用

iOS开发中NSNotification的便利使用

关于iOS开发中NSNotification

iOS 项目中的NSNotification简单使用

iOS开发如何限制NSNotification的作用范围

iOS开发如何限制NSNotification的作用范围