Objective c NSN通知发送一次,但收到多次
我正在两个班级之间与NSNotificationCenter进行交流。我的问题是,尽管我点击了一次按钮(该按钮只会触发一次),但我无意中从一次对NSNotificationCenter的呼叫中生成了越来越多的通知 下面是对该问题的更好解释,代码如下:Objective c NSN通知发送一次,但收到多次,objective-c,cocoa-touch,nsnotificationcenter,Objective C,Cocoa Touch,Nsnotificationcenter,我正在两个班级之间与NSNotificationCenter进行交流。我的问题是,尽管我点击了一次按钮(该按钮只会触发一次),但我无意中从一次对NSNotificationCenter的呼叫中生成了越来越多的通知 下面是对该问题的更好解释,代码如下: 我的两个类是主视图类和菜单类 点击mainView类中的视图时,它将启动一个由菜单创建和管理的视图。初始化mainView时调用此代码: menu=[[MyMenu alloc] init]; UITapGestureRecognizer * t
我的两个类是主视图类和菜单类 点击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];
}
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
- (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;
}
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}
- (void) onChangeItem: (NSNotification*) notification {
NSLog(@"change item to %d",[[[notification userInfo] objectForKey:@"clock"] intValue]);
}
以下是菜单类初始化的方式:
- (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) onTapped: (UIGestureRecognizer*) recognizer {
NSLog(@"tap");
[menu displayMenu];
}
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
- (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;
}
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}
- (void) onChangeItem: (NSNotification*) notification {
NSLog(@"change item to %d",[[[notification userInfo] objectForKey:@"clock"] intValue]);
}
菜单类还有一个clearMenu
方法:
- (void) clearMenu {
[menuView removeFromSuperview];
}
这是UICollectionView中每个单元格的代码,包含在我的菜单类中:
- (void) onTapped: (UIGestureRecognizer*) recognizer {
NSLog(@"tap");
[menu displayMenu];
}
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
- (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;
}
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}
- (void) onChangeItem: (NSNotification*) notification {
NSLog(@"change item to %d",[[[notification userInfo] objectForKey:@"clock"] intValue]);
}
这将调用onButtonTapped:
方法,也在我的菜单中类中:
- (void) onTapped: (UIGestureRecognizer*) recognizer {
NSLog(@"tap");
[menu displayMenu];
}
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
- (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;
}
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}
- (void) onChangeItem: (NSNotification*) notification {
NSLog(@"change item to %d",[[[notification userInfo] objectForKey:@"clock"] intValue]);
}
此通知由mymainView类使用以下代码拾取:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
这将调用mymainView类中的onChangeItem:
方法:
- (void) onTapped: (UIGestureRecognizer*) recognizer {
NSLog(@"tap");
[menu displayMenu];
}
- (void) displayMenu {
[viewForMenu addSubview:menuView];
}
- (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;
}
- (void) onButtonTapped:(UIGestureRecognizer*) recognizer {
NSInteger buttonTapped=[[recognizer view] tag];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemChange" object:nil userInfo:@{@"selected":@(buttonTapped)}];
[self clearMenu];
}
- (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
我第三次听到这个:
...[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次通知-但接收类收到多个通知。 谁能给我解释一下吗
抱歉发了这么长的帖子 好吧,我假设
[[NSNotificationCenter defaultCenter]addObserver:self-selector:@selector(onchangeem:)name:@“ItemChange”object:nil]代码>被多次添加
我喜欢在添加观察者之前删除任何潜在的观察者,如下所示:
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"ItemChange" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeItem:) name:@"ItemChange" object:nil];
这样一来,将只有一个观察者回叫。问题:我遇到了同样的问题,观察者回叫了两次,有时是三次
场景
用户点击注销按钮
HomeViewController
被取消,出现了LoginViewController
屏幕
当用户第二次再次登录时
观察员被叫来两次(有时三次)
问题是[[NSNotificationCenter defaultCenter]removeObserver:self]HomeViewController
的dealloc
方法中的code>根本没有被调用,这实际上会从通知中心一起删除一个对象
ℹ️ <代码>解除锁定
是由
当对象不再为其所有时,对象的Objective-C运行时
应用程序的任何部分
解决方案:创建自己的方法dispose
,并在用户点击注销时调用该方法
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
// ....
}
- (void)dispose {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)logoutTapped {
[self dispose];
// ....
}
其中,在您调用的代码中,[[NSNotificationCenter defaultCenter]addObserver:自选择器:@selector(onChangeItem:)name:@“ItemChange”对象:nil]代码>并删除它?在您的onChangeItem:
方法中,打印正在观察通知NSLog(@“%p”,self)的self
的内存地址代码>并显示您在控制台中看到的内容。这在初始化mainView时调用。所以它只被调用一次。您可以添加NSLog(@“%p”,self)
在您的onChangeItem:
方法中,并向我们展示您在控制台中看到的内容每次重复使用单元格时,您都会向单元格添加一个新的点击手势识别器。在添加一个之前,您应该先检查单元格中是否存在一个。@rdelmar如何检查是否存在一个?@Jimmery如果您对“addObserver”进行全局搜索,每个单元格上方是否有一个“removeObserver:”?哦。好啊我是个白痴,我把你的代码放错地方了。现在,它在正确的地方,它修复了我的错误!非常感谢:)我希望我能提供给你的不仅仅是虚假的互联网积分!我也有同样的问题,但我确信我只调用了addObserver一次,但我得到了两次回调,4年后使用了完全相同的通知对象(通知具有相同的内存地址和内容),并且你得到了更多的假互联网点!这帮我摆脱了困境!