`UIAlertController` is not triggered in NSNotification response - objective-c

This is my AlertView code :
- (void)initializeAlertControllerForOneButtonWithTitle:(NSString *)title withMessage:(NSString *)msg withYesButtonTitle:(NSString *)yesButtonTitle withYesButtonAction:(id)yesButtonAction
{
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:title
message:msg
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* yesBtn = [UIAlertAction
actionWithTitle:yesButtonTitle
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (self.activityIndicator.animating) {
[self.activityIndicator stopAnimating];
}
if ([title isEqualToString:#"Wrong Password!"]) {
self.editTextField.text = #"";
[self.editTextField becomeFirstResponder];
}
}];
[alert addAction:yesBtn];
[self presentViewController:alert animated:YES completion:nil];
}
I am trying to fire this alert in my NSNotificatoin Response method. My Notification Response code :
- (void)receiveSMSVerificationResponse:(NSNotification *)notification
{
SMSVerificationDigitClassModel *smsVerificationDigitClassModel = [[SMSVerificationDigitClassModel alloc] init];
smsVerificationDigitClassModel = [notification object];
if (smsVerificationDigitClassModel.viewControllerName == ViewControllerNameProfileInfoEditViewController) {
if ([self alreadyRegisteredPhoneNumber:smsVerificationDigitClassModel.phoneNumber] == YES) {
NSLog(#"jogajog");
[self initializeAlertControllerForOneButtonWithTitle:#"Already Registered!" withMessage:kAlreadyRegisteredPhoneNumberMSGForChangePhoneNumber withYesButtonTitle:#"Ok" withYesButtonAction:nil];
} else {
if ([AdditionalClasses internetConnectionCheck] == YES) {
self.userModelClass.phone_number = smsVerificationDigitClassModel.phoneNumber;
[self updateUserModel:self.userModelClass];
} else {
[self noInternetConnectionAlert];
}
}
//Check if that phone number is already used
// udate phone numner in server
// update phone number in core data
//[self goToSignUpViewControllerWithPhoneNumber:smsVerificationDigitClassModel.phoneNumber];
}
}
I check it from break point, this line [self initializeAlertControllerForOneButtonWithTitle:#"Already Registered!" withMessage:kAlreadyRegisteredPhoneNumberMSGForChangePhoneNumber withYesButtonTitle:#"Ok" withYesButtonAction:nil]; is actually calling, but the alert view is not popping up. It says:
"Warning: Attempt to present on whose view is not in the window hierarchy!"
I have tried to add notification observer methods :
- (void)addNotificationObserver
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveUserModelResponse:) name:#"sendUpdateRequestToServerForPhoneNumberWithUserModel" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveSMSVerificationResponse:) name:#"SMSVerificationForPhoneNumber" object:nil];
}
In viewDidLoad, viewDidAppear & in viewWillAppear and removeObserver in dealloc,
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"sendUpdateRequestToServerForPhoneNumberWithUserModel" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"SMSVerificationForPhoneNumber" object:nil];
}
but it is not showing at all. So, how do I change my window hierarchy! in this viewController. If you understand, please reply back. A lot of thanks in advance.

Call the initializeAlertControllerForOneButtonWithTitle method inside a main queue dispatch queue block.
All UI operation should be on main threat.
dispatch_async(dispatch_get_main_queue(), ^{
[self initializeAlertControllerForOneButtonWithTitle:#"Already Registered!" withMessage:kAlreadyRegisteredPhoneNumberMSGForChangePhoneNumber withYesButtonTitle:#"Ok" withYesButtonAction:nil];
});

Related

How to handle multiple alerts firing at the same time

I have multiple nsnotificationcenters running at one time that display an alert when triggered. At times, this causes more than one alert to fire at a time but of course you can only display one and the other does not appear. What is the best way handle this situation so multiple alerts can go in succession.
I have tired having the alerts in one method and when one alert is showing, put another notification in an array and then run through that array but that is not working correctly. I have also tried to have the alerts in separate methods but that is not working either.
I have looked at using semaphores but could not find a good example.
This is my notifications which works as expected. I was looking for some advice on the notifications also. Where would be the best place to add the observer, in the viewDidAppear of viewDidLoad. viewDidLoad give a warning whenever an alert is displayed because it wants to display on a view that is not in the hierarchy.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// * 26 APR 2019 * 1.0.4.0
// Add observer for notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"ROC" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"ROP" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"CARGO" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"PAX" object:nil];
}
This is my selector method using a single method for all of the alerts. I am new to coding so I am sure this is not good practice so any advice would be appreciated. I am trying to put any additional notifications in an array if the current view is a uialertcontroller and then run through the array and display those alerts after but that is not working how i would like it to.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// * 26 APR 2019 * 1.0.4.0
// Add observer for notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"ROC" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"ROP" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"CARGO" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"PAX" object:nil];
}
- (void)receivedNotification:(NSNotification *)notification {
NSMutableDictionary *msgData = [[FlightDataInput sharedFlightDataInput] dataForPage:4];
NSMutableArray *alertArray = [[NSMutableArray alloc] init];
if([self.presentedViewController isKindOfClass:[UIAlertController class]]) {
[alertArray addObject:notification];
}
if(![self.presentedViewController isKindOfClass:[UIAlertController class]] && [alertArray count] == 0) {
if([notification.name isEqualToString: #"ROC"]) {
UIAlertController *alertRoc = [UIAlertController alertControllerWithTitle:[msgData valueForKey:#"rocTitle"] message:[msgData valueForKey:#"rocMsg"] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
[alertRoc dismissViewControllerAnimated:YES completion:nil];
}];
[alertRoc addAction:ok];
[self presentViewController:alertRoc animated:NO completion:nil];
}
if ([notification.name isEqualToString:#"ROP"]) {
UIAlertController *alertRop = [UIAlertController alertControllerWithTitle:[msgData valueForKey:#"ropTitle"] message:[msgData valueForKey:#"ropMsg"] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
[alertRop dismissViewControllerAnimated:YES completion:nil];
}];
[alertRop addAction:ok];
[self presentViewController:alertRop animated:NO completion:nil];
}
if ([notification.name isEqualToString:#"CARGO"]) {
UIAlertController *alertCargo = [UIAlertController alertControllerWithTitle:[msgData valueForKey:#"cargoTitle"] message:[msgData valueForKey:#"cargoMsg"] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
[alertCargo dismissViewControllerAnimated:YES completion:nil];
}];
[alertCargo addAction:ok];
[self presentViewController:alertCargo animated:NO completion:nil];
}
if ([notification.name isEqualToString:#"PAX"]) {
UIAlertController *alertPax = [UIAlertController alertControllerWithTitle:[msgData valueForKey:#"paxTitle"] message:[msgData valueForKey:#"paxMsg"] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
[alertPax dismissViewControllerAnimated:YES completion:nil];
}];
[alertPax addAction:ok];
[self presentViewController:alertPax animated:NO completion:nil];
}
}
if([alertArray count] > 0) {
for(int i = 0; i < [alertArray count]; i++) {
// creating the same alerts in here if there are alerts in the array
}
}
}
I have multiple nsnotificationcenters running at one time that display an alert when triggered. At times, this causes more than one alert to fire at a time but of course you can only display one and the other does not appear. What is the best way handle this situation so multiple alerts can go in succession.
I have tired having the alerts in one method and when one alert is showing, put another notification in an array and then run through that array but that is not working correctly. I have also tried to have the alerts in separate methods but that is not working either.
Hi you can present only one Alert at a time. if you want more in chain so first dismiss exist Alerts. Here is Sample please check and update.
{
NSMutableDictionary *msgData;
NSMutableArray <NSNotification *> *alertArray;
int alertIndex;
}
- (void)viewDidLoad:(BOOL)animated {
[super viewDidLoad:animated];
// * 26 APR 2019 * 1.0.4.0
// Add observer for notifications
msgData = [[FlightDataInput sharedFlightDataInput] dataForPage:4];
alertArray = [NSMutableArray new];
alertIndex = 0;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"ROC" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"ROP" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"CARGO" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedNotification:) name:#"PAX" object:nil];
}
- (void)receivedNotification:(NSNotification *)notification {
[alertArray addObject:notification];
if(![self isAlertExist]) {
[self checkAlerts];
}
}
-(void) checkAlerts
{
if(alertIndex < [alertArray count])
{
NSNotification *notification = (NSNotification *)[alertArray objectAtIndex:arrayIndex];
arrayIndex = arrayIndex + 1;
if([notification.name isEqualToString: #"ROC"]) {
[self showAlertWithTitle:[msgData valueForKey:#"rocTitle"] andMessage:[msgData valueForKey:#"rocMsg"]];
}
else if ([notification.name isEqualToString:#"ROP"]) {
[self showAlertWithTitle:[msgData valueForKey:#"ropTitle"] andMessage:[msgData valueForKey:#"ropMsg"]];
}
else if ([notification.name isEqualToString:#"CARGO"]) {
[self showAlertWithTitle:[msgData valueForKey:#"cargoTitle"] andMessage:[msgData valueForKey:#"cargoMsg"]];
}
else if ([notification.name isEqualToString:#"PAX"]) {
[self showAlertWithTitle:[msgData valueForKey:#"paxTitle"] andMessage:[msgData valueForKey:#"paxMsg"]];
}
}
}
-(void) showAlertWithTitle:(NSString *)title andMessage:(NSString *)message
{
UIAlertController *alertPax = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
[alertPax dismissViewControllerAnimated:YES completion:^{
[self checkAlerts];
}];
}];
[alertPax addAction:ok];
[self presentViewController:alertPax animated:NO completion:nil];
}
-(BOOL) isAlertExist {
for (UIWindow* window in [UIApplication sharedApplication].windows) {
if ([window.rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
return YES;
}
}
return NO;
}

UIKeyboardWillShowNotification not working on iOS 7

UIKeyboard will show and hide notification method working fine in iOS8 and later, but it not works in iOS7. Is there any alternative?
My Application Deployment target is iOS7.
My Code is here
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(HideKeyboard:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWasShown:(NSNotification *)sender
{
CGSize kbSize =
[[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
if (!scroll) {
scrollValue = self.WholeScreenUIView.frame.origin.y - kbSize.height;
}
scroll = YES;
}
- (void)HideKeyboard:(NSNotification *)sender
{
scroll = NO;
scrollValue = 0.0;
}
Thanks in advance.
Use this code..
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHideHandler:)
name:UIKeyboardWillHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillshowHandler:)
name:UIKeyboardWillShowNotification
object:nil];
- (void) keyboardWillHideHandler:(NSNotification *)notification {
[scroll setContentOffset:CGPointMake(0, 0) animated:YES];
}
- (void) keyboardWillshowHandler:(NSNotification *)notification {
[scroll setContentSize:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height+44)];
}
Hope this helps.This works in my case

Test NSNotification delivery

I'm trying to make sure the NSNotification gets sent after reportIssue is called.
I get this error:
error: -[APHIssueComposerTests testPopulatedIssueIsReceived] : OCMockObject[APHIssueComposerTests]: expected method was not invoked: reportIssueNotificationReceived
In APHIssueComposer.m:
- (void) reportIssue {
APHIssue* issue = [self issue];
NSNotification* notification = [NSNotification notificationWithName:APHLogDataObjectNotification object:issue];
[[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostWhenIdle];
[self discardIssue];
}
In APHIssueComposerTests.m:
- (void)setUp
{
[super setUp];
self.mockObserver = [OCMockObject mockForClass:[self class]];
[[NSNotificationCenter defaultCenter] addObserver:self.mockObserver
selector:#selector(reportIssueNotificationReceived)
name:APHLogDataObjectNotification
object:nil];
self.issueComposer = [[APHIssueComposer alloc] initWithTempDirectory:#"/my/fake/directory"];
}
- (void)testPopulatedIssueIsReceived
{
[[self.mockObserver expect] reportIssueNotificationReceived];
self.issueComposer.message = #"fake message.";
[self.issueComposer reportIssue];
[mockObserver verify];
[[NSNotificationCenter defaultCenter] removeObserver:mockObserver name:APHLogDataObjectNotification object:nil];
}
- (void)tearDown
{
[super tearDown];
[[NSNotificationCenter defaultCenter] removeObserver:mockObserver name:APHLogDataObjectNotification object:nil];
}
Why doesn't the mock object receive the notification?
The problem is that enqueueNotification is asynchronous.

why isn't removeFromSuperview removing my movie subview? Xcode

I'm trying to get a movie that plays to dismiss on its own without having to hit the "Done" button. I think it's a recent iOS 6 problem since I'm following a tutorial exactly and when I insert NSLogs the NSNotification and removeFromSuperview are being recognized but the movie stays there once it has ended. Here's my code, please help:
- (IBAction)playMovie:(id)sender
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"RomneyFlipSequence1" ofType:#"mov"]];
_moviePlayer =
[[MPMoviePlayerController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayer];
_moviePlayer.controlStyle = MPMovieControlStyleDefault;
_moviePlayer.shouldAutoplay = YES;
[self.view addSubview:_moviePlayer.view];
[_moviePlayer setFullscreen:YES animated:NO];
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
if ([player
respondsToSelector:#selector(setFullscreen:animated:)])
{
[player.view removeFromSuperview];
}
}
#end
You entered the player into fullscreen mode.
[_moviePlayer setFullscreen:YES animated:NO];
Reading other solutions in SO it seems that when you press "Done" the player is taken out of fullscreen first, and then the notification is thrown. After reading this answer, adding
[_moviePlayer setFullscreen:NO animated:YES];
before your removeFromSuperview call will solve your problem.
If the above doesn't work, in addition you may try stoping the player first so the full code will be
-(void)removePlayer:(MPMoviePlayerController *)player{
NSLog(#"Playback Finished");
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:_moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:_moviePlayer];
[_moviePlayer stop]; // <-- May not be needed
if ([_moviePlayer respondsToSelector:#selector(setFullscreen:animated:)])
{
[_moviePlayer setFullscreen:NO animated:YES];
[_moviePlayer.view removeFromSuperview];
}
_moviePlayer=nil;
}
I use the same method for both notifications "Done" and "PlayBackFinished"
Hope this helps.
You had added _moviePlayer.view as a view and you are trying to remove player.view
i think this will do it :
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *player = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
if ([player
respondsToSelector:#selector(setFullscreen:animated:)])
{
[_moviePlayer.view removeFromSuperview];
}
}

NSNotificationCenter is not sending out notifications

I am developing a system to keep track of achievements and for that I use NSNotificationCenter. When an achievement is unlocked in a object in the app a notification is sent to JMAchievementHandler which sets a string to YES and saves the progress in NSUserDefaults. My problem is that the notifications are not working probably. Here is my code in JMAchievementHandler:
- (id)init {
self = [super init];
if (self) {
//Set strings to NO
achievementOne = #"NO";
achievementTwo = #"NO";
achievementThree = #"NO";
achievementFour = #"NO";
//Add observers
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotificationWithName:) name:#"achievement1" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotificationWithName) name:#"achievement2" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotificationWithName) name:#"achievement3" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotificationWithName) name:#"achievement4" object:nil];
//Add observer to observe delegate methods
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotificationFromDelegate:) name:#"notificationLaunch" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotificationFromDelegate:) name:#"notificationEnterBackground" object:nil];
}
return self;
}
- (void)receiveNotificationWithName:(NSNotification *)notification {
if ([[notification name] isEqualToString:#"achievement1"] || [achievementOne isEqualToString:#"NO"]) {
//unlock achievement
NSLog(#"%# is unlocked", [notification name]);
achievementOne = #"YES";
}
else if ([[notification name] isEqualToString:#"achievement2"] || [achievementTwo isEqualToString:#"NO"]) {
//unlock achievement
NSLog(#"%# is unlocked", [notification name]);
achievementTwo = #"YES";
}
else if ([[notification name] isEqualToString:#"achievement3"] || [achievementThree isEqualToString:#"NO"]) {
//unlock achievement
NSLog(#"%# is unlocked", [notification name]);
achievementThree = #"YES";
}
else if ([[notification name] isEqualToString:#"achievement4"] || [achievementFour isEqualToString:#"NO"]) {
//unlock achievement
NSLog(#"%# is unlocked", [notification name]);
achievementFour = #"YES";
}
}
- (void)receiveNotificationFromDelegate:(NSNotification *)notificationDelegate
{
if ([[notificationDelegate name] isEqualToString:#"notificationLaunch"]) {
[self loadDataOnLaunch];
}
else if ([[notificationDelegate name] isEqualToString:#"notificationEnterBackground"]) {
[self saveDataOnExit];
}
}
- (void)loadDataOnLaunch
{
NSLog(#"loadDataOnLaunch");
}
- (void)saveDataOnExit
{
NSLog(#"saveDataOnExit");
}
When I try to post a notification the NSLogs are not called. I use the following code to send notifications from my AppDelegate and ViewController.
- (void)achievement1ButtonPressed:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"achievement1" object:self userInfo:nil];
}
I hope you guys can help me out. Thanks a lot
Jonas
Do you even have a method named receiveNotificationWithName? When you entered the code, the autocomplete should have barfed on that, offering receiveNotificationWithName: instead (unless you wrote it first, without NSNotification*, then added it later...
Anyway, there is a big difference between the two. Also, your handler is buggy. You should revisit that code.
There are lots of reasons to prefer blocks, and this points to one of them. You can just put your code right in the registration, and not worry about giving the wrong selector.
[[NSNotificationCenter defaultCenter] addObserverForName:#"achievement1"
object:nil
queue:nil
usingBlock:^{
// Handle achievement1 right in this little block.
}];
These look like one-shot notifications, so if you want to unregister the notification handler after it runs one time, do this (note the __block).
__block id achievement1 = [[NSNotificationCenter defaultCenter]
addObserverForName:#"achievement1 ":^{
object:nil
queue:nil
usingBlock:^{
// Handle achievement1 right in this little block.
// Remove observer from notification center
[[NSNotificationCenter defaultCenter] removeObserver:achievement1];
}];
All of this looks like it should work (besides the colon, like Andrea mentioned). Is it possible that your button callback isn't being called for a similar reason? I would add an NSLog in your achievement1ButtonPressed: method to make sure.
What I can see is that only one of your addObesrver method call the right selector with the ":", thus the right method signature.