iOS开发 - 监听(NSNotificationCenter)通知出现重复执行的原因

场景:订单提交成功后pop返回上级页面,并弹出下一步功能操作的提示弹窗,多次反复提交订单发现提示弹窗会重复弹出多次,说明通知被监听到了多次。
原因分析:详情页面提交订单成功注册发送通知给列表控制器并pop返回,列表控制器监听到通知后弹窗,这时被监听的通知并没有被移除,再重复操作,由于第一次的被监听通知没有移除,所以后续的操作会一直累加重复监听。

通知的使用步骤:创建通知、发送通知、移除通知

监听通知有两种方法:
1. - (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject

2. - (id )addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block

建议在viewDidLoad方法中创建和监听通知,因为此方法只走一次可防止重复创建

一、- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject方法

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    #1.注册通知监听
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(publishFindGoodsSuccessNotAc:) name:@"PublishPreciseProcurementSuccessNotification"object:nil];
}
#2.监听通知执行方法
- (void)publishFindGoodsSuccessNotAc:(NSNotification *)not{
     NSLog(@"弹窗");
}

#3.发送通知(通知发送时可传参)
[[NSNotificationCenter defaultCenter]  postNotificationName:@"PublishPreciseProcurementSuccessNotification" object:@1];

#4.移除通知
//移除通知一般在dealloc中实现,因为应用支持手势返回,滑回一半又返回等操作,在页面真正销毁的时候移除最合适
//移除有两种方法,一个是移除当前页面所有的通知,一种移除指定的通知,如下:
- (void)dealloc{
     // 移除当前控制器所有通知
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    //移除名为@"PublishPreciseProcurementSuccessNotification"的那个通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"PublishPreciseProcurementSuccessNotification"object:nil];
}

实际中发现dealloc方法有时会不走,一般有以下三种原因可以参考排查

1. ViewController 中有Block,Block里面存在强引用;
2. ViewController 中有关的代理 ,delegate的属性应该用assign/weak修饰;
3. ViewController 中存在NSTimer ,计时器没有及时销毁;

二、- (id )addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block方法

该方法有个block,要操作的步骤可以直接写在block里面 使用较第一种方法方便


///声明通知观察者
@property (weak,   nonatomic) id preciseObserve;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    #1.注册通知监听
    //Name: 通知的名称
    //object:谁发出的通知
    //queue: 队列,决定 block 在哪个线程中执行, nil 在发布通知的线程中执行
    //usingBlock: 只要监听到通知,就会执行这个 block

    #该方法有个block,要操作的步骤可以直接写在block里面 使用较第一种方法方便

    self.preciseObserve = [[NSNotificationCenter defaultCenter]  addObserverForName:@"PublishPreciseProcurementSuccessNotification"object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        @strongify(self);
        [self publishFindGoodsSuccessNotAc:note];
    }];
}

    #2.发送通知(与第一种方法相同)

    #3.移除通知
- (void)dealloc {
    //移除观察者 preciseObserve
    [[NSNotificationCenter defaultCenter] removeObserver:self.preciseObserve];
}
通过比较移除的方法,可以知道,为什么第二种创建通知方法时要有一个id类型的观察者接收值,不要用第一种的注销方法,这也是我出现重复弹框bug的原因,我创建的时候没用一个观察者接收,直接写:
 //用第二种创建监听方法,错误的移除示例
 [[NSNotificationCenter defaultCenter] addObserverForName:@"PublishPreciseProcurementSuccessNotification" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        NSLog(@"收到通知");
        @strongify(self);
        [self publishFindGoodsSuccessNotAc:note];
 }];

导致通知未移除而重复创建,执行方法一次比一次多,而移除的时候用

- (void)dealloc{
    //移除名为PublishPreciseProcurementSuccessNotification的通知
    [[NSNotificationCenter defaultCenter] removeObserver:self.preciseObserve name:@"PublishPreciseProcurementSuccessNotification" object:nil];
}
需要注意销毁应该是哪里监听哪里销毁,不要在发送通知的控制器里执行销毁!!

欢迎大佬儿来指正纠错,共同学习!!

你可能感兴趣的:(iOS开发 - 监听(NSNotificationCenter)通知出现重复执行的原因)