5

To my understanding the object parameter of the addObserver method is the object you want to receive notifications from. Most of the time I see it as nil (I assume this is because notifications of the specified type are wanted from all objects). In my particular case I have a text field at the top of the screen and at the bottom of the screen and I want the view to move up only when the user taps the bottom text field, not the top one. So I call the following method in viewWillAppear

func subscribeToKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: self.bottomTextField)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: self.bottomTextField)
}

the keyboardWillShow: and keyboardWillHide: selectors call methods that do the repositioning of the view's frame. I tried leaving the object parameter to be nil but that would receive notifications from both text fields. I tried setting the object parameter to self.bottomTextField (as seen above) but that doesn't receive notifications from either text field. My question is twofold. First, am I understanding the addObserver method correctly (especially the object parameter) and second, why is it not registering notifications from self.bottomTextField. Thanks!

Solution: I know this isn't the solution to the exact question I was asking but what I did in the end to make the view move up when only clicking on the bottom text field was the following:

func subscribeToKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

and then in the keyboardWillShow: method I have:

func keyboardWillShow(notification: NSNotification) {
    if bottomTextField.editing { // only reset frame's origin if editing from the bottomTextField
        view.frame.origin.y -= getKeyboardHeight(notification)
    }
}

Hopefully that helps!

sbru
  • 877
  • 6
  • 21
  • 36

2 Answers2

3

First, am I understanding the addObserver method correctly (especially the object parameter)

Yes, you've got it. Specifying nil means that you'll get the notification regardless of which object sent it; providing a pointer to an object means that you're observing the notification from that specific object.

second, why is it not registering notifications from self.bottomTextField

You're observing the wrong notification. UITextField never sends UIKeyboardWillShowNotification -- that's a notification that comes from the window. If you specify nil for the object parameter, then you get the notification from any object that sends it, including the window. But when you specified the text field as the object parameter, you didn't get any notification at all because text fields don't send that notification. You should instead observe UITextFieldTextDidBeginEditingNotification and UITextFieldTextDidEndEditingNotification, which are the notifications that UITextField sends.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • @bagelboy Sounds good -- after looking more carefully at your code I updated my answer with the more likely culprit. – Caleb Dec 04 '15 at 07:39
  • ahh that makes sense. Thanks for clarifying! However upon reading the documentation for those notifications, it says "The userInfo dictionary is not used." So how can I access the size of the keyboard to use during the calculations? – sbru Dec 04 '15 at 08:26
  • @bagelboy Look at the other notifications that `UIWindow` sends -- just under `UIKeyboardWillShowNotification` you'll find `UIKeyboardWillChangeFrameNotification`, and that notification has a dictionary with the keyboard size info you're looking for. – Caleb Dec 06 '15 at 07:06
1

Because on your code, the self.bottomTextField did not trigger the notification, but the keyboard, when u pass the sender to the object param, only notifications sent by this sender are delivered to the observer, if u use nil mean it will be receive by all source

To fix your problem, u have to convert your textfield point to get the textfield or use textfield delegate such as textFieldShouldBeginEditing and textFieldShouldEndEditing which have textfield param with it

The category to get the current responder textfield:

#import "UIResponder+FirstResponder.h"

static __weak id currentFirstResponder;

@implementation UIResponder (FirstResponder)

+(id)currentFirstResponder {
    currentFirstResponder = nil;
    [[UIApplication sharedApplication] sendAction:@selector(findFirstResponder:) to:nil from:nil forEvent:nil];
    return currentFirstResponder;
}

-(void)findFirstResponder:(id)sender {
    currentFirstResponder = self;
}
Tj3n
  • 9,837
  • 2
  • 24
  • 35
  • 1
    I don't quite understand what you mean in the first sentence. Do you mean that `self.bottomTextField` doesn't trigger the notification but rather it calls for the keyboard to show and the keyboard calls the notification? And so when I use nil it will pick up that notification from the keyboard? In terms of fixing the problem, what do you mean by "you have to convert your textfield point to get the textfield"? – sbru Dec 04 '15 at 07:31
  • Yes, you understand correctly, but when u pass in object param, it will only observe that object, but when its nil, it will observe from all source, mean any object trigger that will call to the selector, for me to fix it, i got an category in `UIResponder` that return the current responder (that textfield with keyboard) and working with it – Tj3n Dec 04 '15 at 07:34