I am communicating between two classes with NSNotificationCenter. My problem is that although I tap a button once (and that button only fires off once) I am unintentionally producing increasing numbers of notifications from only one call to the NSNotificationCenter.
我正在使用NSNotificationCenter在两个类之间进行通信。我的问题是,虽然我点击一次按钮(并且该按钮仅触发一次)但我无意中仅通过一次调用NSNotificationCenter产生了越来越多的通知。
Here is a better explanation of the problem, with code:
以下是对问题的更好解释,代码如下:
My two classes are the mainView class and the Menu class.
我的两个类是mainView类和Menu类。
When a view in the mainView class is tapped, it launches a view created and governed by the Menu class. This code is called when the mainView is initialized:
当轻触mainView类中的视图时,它将启动由Menu类创建和管理的视图。初始化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];
This Gesture Recognizer fires off this method, also in the mainView class:
这个Gesture Recognizer在mainView类中触发了这个方法:
- (void) onTapped: (UIGestureRecognizer*) recognizer {
NSLog(@"tap");
[menu displayMenu];
}
This is how the Menu class initializes:
这是Menu类初始化的方式:
- (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;
}
And this is the displayMenu
method inside the Menu class:
这是Menu类中的displayMenu方法:
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
The Menu class also has a clearMenu
method:
Menu类还有一个clearMenu方法:
- (void) clearMenu {
[menuView removeFromSuperview];
}
This is the code for each cell in the UICollectionView, contained within my Menu class:
这是UICollectionView中每个单元格的代码,包含在我的Menu类中:
- (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;
}
This calls the onButtonTapped:
method, also within my Menu class:
这会在我的Menu类中调用onButtonTapped:方法:
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}
This notification is picked up by my mainView class with this code:
我的mainView类使用以下代码获取此通知:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
This calls the onChangeItem:
method, inside my mainView class:
这将调用我的mainView类中的onChangeItem:方法:
- (void) onChangeItem: (NSNotification*) notification {
NSLog(@"change item to %d",[[[notification userInfo] objectForKey:@"clock"] intValue]);
}
So that's the code.
这就是代码。
OK, here's the problem: the first time the menu displays I get this in my log:
好的,这是问题所在:第一次显示菜单我在日志中得到了这个:
...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
And this is fine, this is what I expect. However second time around I get this:
这很好,这是我所期待的。但是第二次我得到这个:
...[43023:11f03] tap
...[43023:11f03] button tapped : 1
...[43023:11f03] change item to 1
...[43023:11f03] change item to 1
Third time around I get this:
我第三次得到这个:
...[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
And so on. Each successive tap on a menu item doubles the amount of notification calls.
等等。菜单项上的每次连续点击都会使通知呼叫量加倍。
To begin with I thought I was adding multiple views, and thus resulting in multiple button taps, and therefore multiple notifications calls.
首先,我认为我正在添加多个视图,从而导致多个按钮点击,因此多个通知调用。
However as you can see from my logs, this is not the case. The buttons are only receiving 1 tap event - this is firing off only 1 notification - but receiving class gets sent multiple notifications.
但是,从我的日志中可以看出,情况并非如此。这些按钮只接收1个点击事件 - 这只会触发1个通知 - 但接收类会收到多个通知。
Can anyone explain this to me?
任何人都可以向我解释这个吗?
Sorry for the lengthy post!
对不起,这个冗长的帖子!
1 个解决方案
#1
32
Well, I am assuming that [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
are being added more than once.
好吧,我假设[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem :) name:@“ItemChange”object:nil];被添加不止一次。
I like to remove any potential observer before adding an observer, like so:
我想在添加观察者之前删除任何潜在的观察者,如下所示:
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"ItemChange" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
That way there will ever only be one observer callback.
那样只会有一个观察者回调。
#1
32
Well, I am assuming that [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
are being added more than once.
好吧,我假设[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem :) name:@“ItemChange”object:nil];被添加不止一次。
I like to remove any potential observer before adding an observer, like so:
我想在添加观察者之前删除任何潜在的观察者,如下所示:
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"ItemChange" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
That way there will ever only be one observer callback.
那样只会有一个观察者回调。