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

• 在 vi​​ewWillDisappear 中添加了“取消订阅”

• 在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 因为iOS9developer.apple.com/documentation/foundation/…,所以不需要手动删除dealloc中的观察者 @Kamil.S,谢谢,我知道。我所有的应用程序都兼容 iOS 8。不过,一个很好的说明。

以上是关于Obj-C - NSNotification 执行两次?的主要内容,如果未能解决你的问题,请参考以下文章

对由 NSTimer 异步发送的 NSNotification 进行单元测试

NSNotification的使用 & 和代理的区别

使用 iOS/Obj-c 按类型搜索 Apple App Store

Obj-C - didSelectRowAtIndexPath没有开火?

Obj-C - 添加活动指示器以下拉刷新?

NSNotification消息