Obj-C - NSNotification executing twice? - ios

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

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)
}

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.

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);

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];
}

Related

keyboard notification not called in ios 11.3

I have keyboard notification in my App and its working fine in ios 10 but my notification method not called in ios11.3
Below is my code:
- (void)attach {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWasShown:(NSNotification*)aNotification {
UIView* responder = [self findFirstResponder];
if (responder) {
_tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapAnywhere:)];
[baseView addGestureRecognizer:_tapRecognizer];
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
CGRect screenRect = [RGLayout layout].fullScreen;
CGRect frame = responder.frame ;
}
}
I have tried to find the solution and i got that the only changes in iOS11 is UIKeyboardFrameEndUserInfoKey for keyborad height.
But my problem is that my keyboardWasShown not called in ios11.3 same code is working ios 10.2
FYI: when user click on next the next textField will becomeFirstResponder.
Don't know why but the behaviour is strange the notification is calling in one screen and not in another screen.
I have solve the issue by following code:
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if (self.nextField) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.nextField becomeFirstResponder];
[[NSNotificationCenter defaultCenter] postNotificationName: UIKeyboardDidShowNotification object:self];
});
}
else{
dispatch_async(dispatch_get_main_queue(), ^{
[textField resignFirstResponder] ;
});
}
return NO ;
}

Add UISearchBar above keyboard

I want to display a search bar above the keyboard. Whenever the keyboard appears search bar should also come. How to do this?
You can simply use textField.inputAccessoryView = your search bar
textField.inputAccessoryView = mySearchBar;
Create an object of UISearch bar and add an observer for keyboard in textFieldDidBeginEditing/textViewDidBeginEditing
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
}
- (void)keyboardWasShown:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
int height = MIN(keyboardSize.height,keyboardSize.width);
int width = MAX(keyboardSize.height,keyboardSize.width);
//set frame for searchbar
searchBar.frame = CGRectMake(0, self.view.frame.size.height - height, width, 50);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -keyboardSize.height;
self.view.frame = f;
}];
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}

raising keyboard pressing on a text field

I want to raise my keyboard when i press on a determinate UITextField, so I create a touch down action, but at the first call it doesn't work, by second call it work fine.
here's the code (naturally keyboardSize is a global variable with CGSize type):
- (void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self moveFrameToVerticalPosition:0.0f forDuration:0.3f];
}
- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration {
CGRect frame = self.view.frame;
frame.origin.y = position;
[UIView animateWithDuration:duration animations:^{
self.view.frame = frame;
}];
}
- (IBAction)insert:(id)sender {
float newVerticalPosition = - keyboardSize.height;
[self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.0f];
}
In keyboardWillShow: add:
[self moveFrameToVerticalPosition:-keyboardSize.height forDuration:0.0f];
You don't really need insert:.

Whatsapp style - keyboard appear under the toolbar

How do I do it whatsapp style, where the message space, when clicked, would push a keyboard up from the bottom, as well as pushing the toolbar up as well. And then when cancelled (i.e. clicking in the background), it'll push the keyboard back down with the toolbar
This is done with the UIKeyboardWillShowNotification, UIKeyboardDidShowNotification, UIKeyboardWillHideNotification and UIKeyboardDidHideNotification notifications.
Then when you handle the notification you adjust the height of the frame:
For example:
- (void) keyboardWillShow:(NSNotification *)aNotification{
NSDictionary* info = [aNotification userInfo];
NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
NSValue* aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
CGFloat keyboardHeight = [aValue CGRectValue].size.height;
self.keyboardVissible = YES;
[UIView animateWithDuration:duration animations:^{
CGRect frame = self.contentView.frame;
frame.size.height -= keyboardHeight;
self.contentView.frame = frame;
}];
}
You will need to register to receive the notification, you should only listen to the keyboard notification when the view is visible, strange thing could happen if you do it in the viewDidLoad:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void) viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

App is crashing when moving to other app and then moving back

I have an issue with my app..
It's crashing when i'm using home button for multitasking to move to another app and when i want to go back again to my app it's crashing and i get the message:
*** -[UIView convertRect:toView:]: message sent to deallocated instance 0x81e4020
It started since i've implemented "inner-view" ad's.
do i need to do something in my code to make it disspapear?
I tried to solve it but no success.
This is my code of the ad's:
CGRect frame = CGRectMake(0, 480, 320, 50);
self.adBanner = [[UIView alloc] initWithFrame:frame];
[self.view convertRect:adBanner.frame toView:nil]; --->This is a line i tried to put...
[self.view addSubview:self.adBanner];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdReceived:) name:#"iaAdReceived" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaDefaultAdReceived:) name:#"iaDefaultAdReceived" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdFailed:) name:#"IaAdFailed" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdClicked:) name:#"IaAdClicked" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillShow:) name:#"IaAdWillShow" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidShow:) name:#"IaAdDidShow" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillHide:) name:#"IaAdWillHide" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidHide:) name:#"IaAdDidHide" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillClose:) name:#"IaAdWillClose" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidClose:) name:#"IaAdDidClose" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillResize:) name:#"IaAdWillResize" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidResize:) name:#"IaAdDidResize" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillExpand:) name:#"IaAdWillExpand" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidExpand:) name:#"IaAdDidExpand" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAppShouldSuspend:) name:#"IaAppShouldSuspend" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAppShouldResume:) name:#"IaAppShouldResume" object:nil];
// Display ad
if (![InneractiveAd DisplayAd:#"iOS_Test" withType:IaAdType_Banner withRoot:self.adBanner withReload:60 withParams:optionalParams])
{
[adBanner removeFromSuperview];
}
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[adBanner removeFromSuperview];
}
- (IBAction)iaAdReceived:(id)sender
{
// The ad view has finished loading a paid ad
}
- (IBAction)iaDefaultAdReceived:(id)sender
{
// The ad view has finished loading a default ad
}
- (IBAction)iaAdFailed:(id)sender
{
// The ad view has failed to load an ad
}
- (IBAction)iaAdClicked:(id)sender
{
// The ad has been clicked
}
- (IBAction)iaAdWillShow:(id)sender
{
// The ad is about to show
}
- (IBAction)iaAdDidShow:(id)sender
{
// The ad did show
}
- (IBAction)iaAdWillHide:(id)sender
{
// The ad is about to hide
}
- (IBAction)iaAdDidHide:(id)sender
{
// The ad did hide
}
- (IBAction)iaAdWillClose:(id)sender
{
// The ad is about to close
}
- (IBAction)iaAdDidClose:(id)sender
{
// The ad did close
}
- (IBAction)iaAdWillResize:(id)sender
{
// The ad is about to resize
}
- (IBAction)iaAdDidResize:(id)sender
{
// The ad did resize
}
- (IBAction)iaAdWillExpand:(id)sender
{
// The ad is about to expand
}
- (IBAction)iaAdDidExpand:(id)sender
{
// The ad did expand
}
- (IBAction)iaAppShouldSuspend:(id)sender
{
// The app should suspend (for example, when the ad expands)
}
- (IBAction)iaAppShouldResume:(id)sender
{
// The app should resume (for example, when the ad collapses)
}
I attached a screenshot...
What could it be?
Thanks...
Your problem is that when running :
[self.view convertRect:adBanner.frame toView:nil];
your view doesn't exists anymore.
in your appDelegate you should work on this method :
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
anyway, what did you try to achieve with this line ? because it's returning a CGRect which you're not using.

Resources