【问题标题】:Obj-C - NSNotification executing twice?Obj-C - NSNotification 执行两次?
【发布时间】: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 会延续到另一个视图?
  • 监听键盘是全局的,所以当键盘显示在另一个监听它的视图控制器中时,如果它没有被释放,那个视图控制器就会打印出来

标签: ios objective-c


【解决方案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。不过,一个很好的说明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 2011-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多