Obj-C - NSNotification 执行两次?
Posted
技术标签:
【中文标题】Obj-C - NSNotification 执行两次?【英文标题】:Obj-C - NSNotification executing twice? 【发布时间】:2018-02-06 08:40:36 【问题描述】:由于某种原因,UIKeyboardWillHideNotification 在我下面的代码中被执行了两次——我不知道为什么。我知道这一点是因为我的 NSLog(“关闭!”)在我的控制台中出现了两次。我是否遗漏了一些明显的东西(不,我没有第二次将 UIKeyboardWillHideNotification 粘贴到我的代码中)。
-(void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboard:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboard:) name:UIKeyboardWillShowNotification object:nil];
- (void)handleKeyboard:(NSNotification*)aNotification
NSDictionary* info = [aNotification userInfo];
NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 3;
[value getValue:&duration];
if (aNotification.name == UIKeyboardWillShowNotification)
self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight);
[self moveCustomView:YES duration:duration];
if (aNotification.name == UIKeyboardWillHideNotification)
/** KEYBOARD HIDE **/
self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight);
[self moveCustomView:NO duration:duration];
NSLog(@"CLOSED!");
【问题讨论】:
无关备注:请使用isEqual:
或isEqualToString:
比较字符串。 ==
导致指针比较,并可能导致错误(假阴性)。
我已复制您的代码并粘贴到我的项目中,但它对我有用。没有任何问题。只调用了一次。
点击文本字段UIKeyboardWillShowNotification
调用1次..返回文本字段UIKeyboardWillHideNotification
调用1次..
多么奇怪@NiravKotecha - 也许我在不同的视图控制器中有一些东西会影响这个?可能的?虽然我不认为 UIKeyboardWillHide 会延续到另一个视图?
监听键盘是全局的,所以当键盘显示在另一个监听它的视图控制器中时,如果它没有被释放,那个视图控制器就会打印出来
【参考方案1】:
确保删除 viewDidDisappear 中的观察者,因为某些原因可能不会重新分配视图控制器,并且 viewDidLoad 中的代码会在添加两次观察者时执行两次
// 目标c
- (void)viewWillDisappear:(BOOL)paramAnimated
[super viewWillDisappear:paramAnimated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
// 斯威夫特
override func viewDidDisappear(_ animated: Bool)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
【讨论】:
补充一点:这种情况下需要将通知订阅移动到viewDid(Will)Appear而不是DidLoad,否则返回视图时会停止接收通知。 如何移除观察者?不知道那段代码是什么样子的(对不起,新人哈哈) 我从我的初始视图控制器中删除了观察者,并且没有骰子。但是,如果我在 if 语句(if == hideKeyboard)中删除观察者,它会在我第一次隐藏我的键盘时起作用,但不是第二次。有没有什么地方可以删除包含我的 textView 的视图控制器中的观察者?【参考方案2】:一定要从 dealloc 方法中移除观察者。如果你不删除它并且它的内存没有被释放,它会监听其他页面上的键盘行为。此外,您不应向同一个观察者添加两次相同的通知。
【讨论】:
自 ios 9 以来,不再需要在 dealloc 中移除(非基于块的)观察者。 感谢您的提醒。但是我的应用支持iOS 8,dealloc中的操作可能是习惯问题。【参考方案3】:而不是使用相同的方法来隐藏和显示通知。您可以使用两种不同的方法。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
现在,为了改变你的框架,你可以使用以下代码
NSDictionary* info = [aNotification userInfo];
CGSize *kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -kbSize.height);
【讨论】:
使用上述代码关闭键盘时出现同样的问题(隐藏通知执行两次)。【参考方案4】:请尝试一下:
我做了什么:
• 将订阅移至 viewWillAppear
• 在 viewWillDisappear 中添加了“取消订阅”
• 在dealloc
中添加了“取消订阅”(应该与您的问题无关,但这仍然是正确的做法)
• 在您的处理程序中将 == 替换为 isEqual(也很可能与您的问题无关)。
那里可能有一些错别字。对不起,如果是这样的话。
-(void)viewWillAppear
[super viewWillAppear];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboard:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboard:) name:UIKeyboardWillShowNotification object:nil];
-(void)viewDidLoad
[super viewDidLoad];
//Leaving this method here just to point out that everything was moved to viewWillAppear
- (void)handleKeyboard:(NSNotification*)aNotification
NSDictionary* info = [aNotification userInfo];
NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 3;
[value getValue:&duration];
if ([aNotification.name isEqual: UIKeyboardWillShowNotification])
self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight);
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight);
[self moveCustomView:YES duration:duration];
if ([aNotification.name isEqual: UIKeyboardWillHideNotification])
/** KEYBOARD HIDE **/
self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight);
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight);
[self moveCustomView:NO duration:duration];
NSLog(@"CLOSED!");
-(void)unsubscribe
[[NSNotificationCenter defaultCenter] removeObserver:self];
-(void)viewWillDisappear
[super viewWillDisappear];
[self unsubscribe];
-(void)dealloc
[self unsubscribe];
【讨论】:
@Brittany,代码本身应该没问题。我尝试使用谷歌搜索UIKeyboardWillHideNotification is posted twice
,似乎其他人在滚动/屏幕旋转时遇到了类似的问题(不确定)。抱歉,我的回答没有多大帮助,但如果您尝试查找我提到的请求的信息,它可能会有所帮助。
@FreeNickname 因为iOS9
developer.apple.com/documentation/foundation/…,所以不需要手动删除dealloc中的观察者
@Kamil.S,谢谢,我知道。我所有的应用程序都兼容 iOS 8。不过,一个很好的说明。以上是关于Obj-C - NSNotification 执行两次?的主要内容,如果未能解决你的问题,请参考以下文章
对由 NSTimer 异步发送的 NSNotification 进行单元测试
使用 iOS/Obj-c 按类型搜索 Apple App Store