0

For some reason, UIKeyboardWillHideNotification is being executed twice in my below code - I haven't a clue as to why. I know this because my NSLog ("Closed!") appears twice in my console. Am I missing something obvious (and no, I don't have UIKeyboardWillHideNotification pasted somewhere in my code a second time).

-(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!");
    }


}
Arasuvel
  • 2,971
  • 1
  • 25
  • 40
Brittany
  • 1,359
  • 4
  • 24
  • 63
  • 3
    Un unrelated remark: please, use `isEqual:` or `isEqualToString:` to compare strings. `==` results in a pointer comparison, and may lead to an error (false negative). – FreeNickname Feb 06 '18 at 08:43
  • i have copied your code and pasted in my project but its works for me. no issue. only one time called. – Nirav Kotecha Feb 06 '18 at 08:50
  • click on textfield `UIKeyboardWillShowNotification` call 1 time.. return textfield `UIKeyboardWillHideNotification` call 1 time.. – Nirav Kotecha Feb 06 '18 at 08:51
  • How strange @NiravKotecha - perhaps I have something in a different viewcontroller that's affecting this? Possible? Though I don't think UIKeyboardWillHide would carry over into another view? – Brittany Feb 06 '18 at 08:52
  • @NiravKotecha I don't see this option (it's a textView not field)? – Brittany Feb 06 '18 at 08:53
  • 2
    listen to keyboard is global so when keyboard shown in another viewController that listens to it , that view controller prints if it's not deallocated – Shehata Gamal Feb 06 '18 at 08:53
  • textview also one time – Nirav Kotecha Feb 06 '18 at 08:58
  • In viewWillDisappear or while going to next viewController remove UIKeyboardWillShowNotification and UIKeyboardWillHideNotification observer from current controller. – Sharad Chauhan Feb 06 '18 at 09:02
  • One thing I have noticed is that showing an alert box or action sheet just after the keyboard has closed (maybe after checking the text content of the edit) causes a second spurious UIKeyboardWillHide notification to be sent, even though the keyboard is not up – Paulus Apr 12 '18 at 13:53

4 Answers4

0

Make sure to remove observers in viewDidDisappear as , view controller may be not reallocated from some reason and code in viewDidLoad is executed twice as observer is added twice

// Objective c

 - (void)viewWillDisappear:(BOOL)paramAnimated{
   [super viewWillDisappear:paramAnimated];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]  removeObserver:self name:UIKeyboardWillHideNotification object:nil];

}

// Swift

 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)


}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • An addition: in this case you need to move the notification subscription to viewDid(Will)Appear instead of DidLoad, otherwise it would stop receiving notifications when you returned to the view. – FreeNickname Feb 06 '18 at 09:03
  • How do I remove observers? Not sure what that code looks like (sorry, newb lol) – Brittany Feb 06 '18 at 09:05
  • I removed the observer from my initial view controller, and no dice. However, if I remove the observer inside of my if statement (if == hideKeyboard), it works the first time I hide my keyboard, but not the second. Is there somewhere I can remove the observer in the viewcontroller that contains my textView? – Brittany Feb 06 '18 at 09:14
0

Be sure to remove the observer from the dealloc method. If you do not remove it and its memory is not released, it will listen for keyboard behavior on other pages. In addition, you should not add the same notification twice to the same observer.

Jack Liu
  • 17
  • 1
  • Removing (non-Block-based) observers in dealloc has not been necessary since iOS 9. – jscs Feb 06 '18 at 13:51
  • 1
    Thanks for your reminder. But my app supports iOS 8, the operation in dealloc may be a matter of habit. – Jack Liu Feb 07 '18 at 01:14
0

Instead of Using same method for Hide and show notification. You can use two different Methods.

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];

Now, for Change your frame You can use following code

NSDictionary* info = [aNotification userInfo];
   CGSize *kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -kbSize.height); 
Mansur
  • 187
  • 2
  • 12
0

Please, try it like this:

What I did:

• moved subscription to viewWillAppear

• added "unsubscribe" in viewWillDisappear

• added "unsubscribe" in dealloc (shouldn't be related to your issue, but that's the right way to do it still)

• replaced == with isEqual in your handler (also not related to your issue, most likely).

There may be some typos there. Sorry, if that's the case.

-(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];
}
FreeNickname
  • 7,398
  • 2
  • 30
  • 60
  • @Brittany, the code itself should be fine. I tried googling `UIKeyboardWillHideNotification is posted twice`, and it seems that other people ran into similar issues, when scrolling was happening / screen was rotated (not sure). Sorry that my answer wasn't much help, but if you tried looking up info on the request I mentioned, it might be helpful. – FreeNickname Feb 07 '18 at 12:48
  • @FreeNickname it's not necessary to manually remove observers in dealloc since `iOS9` https://developer.apple.com/documentation/foundation/nsnotificationcenter/1407263-removeobserver – Kamil.S Feb 10 '18 at 19:57
  • @Kamil.S, thanks, I know. All my apps are iOS 8-compatible. Still, a good note. – FreeNickname Feb 12 '18 at 05:59