How to receive 2 notifications via NSNotificationCenter - objective-c

I have three methods:
- (void)viewDidAppear:(BOOL)animated
{
[self updateViews];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"itemQuantityChanged" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:[NSString stringWithFormat:#"Item %# deleted", itemUUID] object:nil];
}
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void) receiveNotification: (NSNotification *)notification
{
if ([[notification name] isEqualToString:#"itemQuantityChanged"])
[self updateViews];
if ([[notification name] isEqualToString:[NSString stringWithFormat:#"Item %# deleted", itemUUID]])
NSLog(#"FAIL!");
}
The main idea is that for this class I need to receive 2 different notifications and in case of receiving them need to perform different actions. Is everything ok with the realization? I believe that it is possible to simplify this code. How to removeObserver correctly? I don't use ARC.

You should use a different selector for each notification. That way, you don't need any logic in the method to determine which notification was sent.
Removing the observers as you are doing is fine.

Related

`UIAlertController` is not triggered in NSNotification response

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

Crash when posting NSNotification after In-App Purchase

I am very familiar with notifications but I get a crash without any reason, after using the In-App Purchase (I doubt that it relates to it anyway).
So when the user is done purchasing,this function is being called :
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];
// i get the crash here when trying to post the notification.
}
Now ,the main scene that has the observer, is setted on start with :
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(productPurchased:) name:IAPHelperProductPurchasedNotification object:nil];
Is it because the object set to nil on the observer? what should it be ?
I would suggest putting the Info into the userInfo like this:
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:nil userInfo:#{#"identifier": productIdentifier}];
// i get the crash here when trying to post the notification.
}
Then you can observe the NSNotification with
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(productPurchased:) name:IAPHelperProductPurchasedNotification object:nil];
In -(void) productPurchased:(NSNotification*)notification you can get the info back:
-(void) productPurchased:(NSNotification*)notification {
NSString *productIdentifier = [notification.userInfo valueForKey:#"identifier"];
}
This problem could occur because you have an nil object as an NSNotification observer.
It is often good remove self from the NSNotificationCenter's observer list when the object deallocates.
Add this
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
in all classes that is an observer for notifications. (Note that there might be other places that you want to remove the observer. E.g. in viewDidDisappear)

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.

Check if Multiple WebViews have finished Load

I am currently using NSNotificationCentre to pass the WebViewStart and WebViewFinish events for 5 WebViews.
Inside the WebViewStart method I start the animation of a progress bar.
Inside the WebViewFinish method I stop the animation of a progress bar.
Obviously the problem is that if 5 WebViews are loading, and one WebView finishes loading, it fires the WebViewFinish method and stops the animation, even though the other WebViews are still loading.
Is there any way to check something like the following?
- (void)_webViewProgressFinished:(NSNotification *)notification
{
if ([webView1 & webView2 & webView3 finishedLoading]) {
[_loadingIndicator stopAnimation:self];
}
}
The code I have at the moment doesn't seem appropriate for the number of WebViews I have. The code I am using at the moment and having problems with is as follows:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_mainWebView];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_mainWebView];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView1];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView1];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView2];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView2];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView3];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView3];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView4];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView4];
}
- (void)_webViewProgressStarted:(NSNotification *)notification
{
[_loadingIndicator startAnimation:self];
}
- (void)_webViewProgressFinished:(NSNotification *)notification
{
[_loadingIndicator stopAnimation:self];
}
I hope someone can help. Thanks in advance everyone!
EDIT: I ended up finding the solution myself. May not be the most elegant, but nevertheless:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_mainWebView];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_mainWebView];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView1];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView1];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView2];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView2];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView3];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView3];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressStarted:) name:WebViewProgressStartedNotification object:_subWebView4];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_webViewProgressFinished:) name:WebViewProgressFinishedNotification object:_subWebView4];
}
- (void)_webViewProgressStarted:(NSNotification *)notification
{
if ([_mainWebView isEqual:[notification object]]) {
[_mainWebViewProgress startAnimation:self];
} else if ([_subWebView1 isEqual:[notification object]]) {
[_subView1Progress startAnimation:self];
} else if ([_subWebView2 isEqual:[notification object]]) {
[_subView2Progress startAnimation:self];
} else if ([_subWebView3 isEqual:[notification object]]) {
[_subView3Progress startAnimation:self];
} else if ([_subWebView4 isEqual:[notification object]]) {
[_subView4Progress startAnimation:self];
}
}
What this does is gets the notification object, which is an ID, and compares it to our WebViews. If they are the same, then that WebView has started/finished load.
Hope this helps anyone.
Create a separate notification for each of the 5 web views. Create 5 boolean values that can be set to true as each web view is finished. When a web view finishes, have the notification center post it's notification. The method that receives this notification should first set it's boolean value to true saying that it finished. Then check to see if all 5 boolean values are set to true. If yes, stop the activity indicator. If no, leave it spinning.
You could just count until you get 5 notifications. you could also estimate progress as the views finish one at a time, Nx20% for the aggregate in percentage.

Print Notifications

How can I print every single notification on my system in obj-C?
[[NSNotificationCenter defaultCenter] addObserver:self ...];
what does in "..."? Should I use NSDistributedNotificationCenter?
let's say I have a function called logfunc which will do NSLog(#"ok");
thank you
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethod:) name:nil object:nil];
You can then define a method that matches your selector, like this:
- (void)myMethod:(NSNotification *)notification {
NSLog(#"notification received: %#", notification);
}