NSNotification发送一次,但是多次收到

时间:2013-08-07 15:47:59

标签: objective-c cocoa-touch nsnotificationcenter

我正在使用NSNotificationCenter在两个类之间进行通信。我的问题是,虽然我点击一次按钮(并且该按钮仅触发一次)但我无意中仅通过一次调用NSNotificationCenter产生了越来越多的通知。

以下是对问题的更好解释,代码为:


我的两个课程是 mainView 课程和菜单课程。

点击 mainView 类中的视图后,它会启动由菜单类创建并管理的视图。初始化 mainView 时会调用此代码:

menu=[[MyMenu alloc] init];
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapped:)];
[tap setNumberOfTapsRequired:1];
[container addGestureRecognizer:tap];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];

这个手势识别器会在 mainView 类中触发此方法:

- (void) onTapped: (UIGestureRecognizer*) recognizer {
    NSLog(@"tap");
    [menu displayMenu];
}

这是菜单类初始化的方式:

- (MyMenu*) init {
    self=[super init];
    UICollectionViewFlowLayout * layout=[[UICollectionViewFlowLayout alloc] init];
    menuView=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 200, 200) collectionViewLayout:layout];
    [menuView setDataSource:self];
    [menuView setDelegate:self];
    [menuView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    [menuView setAutoresizesSubviews:YES];
    [menuView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
    [menuView setBackgroundColor:[UIColor clearColor]];
    [menuView setIndicatorStyle:UIScrollViewIndicatorStyleWhite];
    return self;
}

这是菜单类中的displayMenu方法:

- (void) displayMenu {
    [viewForMenu addSubview:menuView];
}

菜单类还有一个clearMenu方法:

- (void) clearMenu {
    [menuView removeFromSuperview];
}

这是UICollectionView中每个单元格的代码,包含在菜单类中:

- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    [cell setTag:indexPath.row];
    UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)];
    [tap setNumberOfTapsRequired:1];
    [cell addGestureRecognizer:tap];
    NSLog(@"button tapped : %d",indexPath.row);
    return cell;
}

这会在我的菜单类中调用onButtonTapped:方法:

- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
    NSInteger buttonTapped=[[recognizer view] tag];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}

我的 mainView 类会使用以下代码获取此通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];

这会在我的 mainView 类中调用onChangeItem:方法:

- (void) onChangeItem: (NSNotification*) notification {
    NSLog(@"change item to %d",[[[notification userInfo] objectForKey:@"clock"] intValue]);
}

这就是代码。


好的,这就是问题:第一次显示菜单我在日志中得到了这个:

...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1

这很好,这就是我的期望。但是第二次我得到了这个:

...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1

我第三次得到这个:

...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1

等等。菜单项上的每次连续点击都会使通知呼叫量加倍。


首先,我认为我正在添加多个视图,从而导致多个按钮点按,因此会有多个通知调用。

但是从我的日志中可以看出,情况并非如此。 这些按钮只接收1个点击事件 - 这只会触发1个通知 - 但接收类会收到多个通知。

任何人都可以向我解释这个吗?

很抱歉这篇冗长的帖子!

2 个答案:

答案 0 :(得分:32)

好吧,我假设[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];被多次添加。

我喜欢在添加观察者之前删除任何潜在的观察者,如下所示:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"ItemChange" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];

这样只会有一个观察者回调。

答案 1 :(得分:1)

问题:我遇到了同样的问题,观察者打了两次,有时是三次。

  

场景

     
      
  1. 用户点击注销按钮
  2.   
  3. HomeViewController被撤消,并显示了LoginViewController屏幕
  4.   
  5. 当用户第二次登录时
  6.   
  7. 观察员被叫两次(有时三次)
  8.   

问题是我的[[NSNotificationCenter defaultCenter] removeObserver:self];的{​​{1}}方法中的dealloc根本没有被调用,实际上是从通知中心一起删除了一个对象。

  

ℹ️HomeViewController是一个Objective-C选择器,由   当对象不再归对象所有时,Objective-C运行时   应用程序的任何部分。

解决方案:制作了自己的方法dealloc,并在用户点击dispose时调用它。

logout