The difference between these two scheduled method calls - iOS - ios

I have seen this around a few times but can't seem to find what is the difference between the two ...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loginViewFetchedUserInfo:)
name:FBSDKProfileDidChangeNotification
object:nil];
- (void)loginViewFetchedUserInfo:(NSNotification *)notification
and
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loginViewFetchedUserInfo)
name:FBSDKProfileDidChangeNotification
object:nil];
- (void)loginViewFetchedUserInfo
I know that (void)methodname:(TYPE *)newName can pass in a value to the method but I don't know what the difference is in the two above and why you would do the first one (which is used in the Facebook SDK example) over the second one.

The first method passes the NSNotification object to the method. This way allows you to access information about the notification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loginViewFetchedUserInfo:)
name:FBSDKProfileDidChangeNotification
nil];
For example, if the notification was posted with a userInfo dictionary
NSDictionary *userInfo = #{#"Blah" : #"foo"};
[[NSNotificationCenter defaultCenter] postNotificationName:FBSDKProfileDidChangeNotification object:self userInfo:userInfo];
and you wanted to access userInfo in the method. You can also access the sender of the notification, which would be the notification's object.
- (void)loginViewFetchedUserInfo:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSObject *sender = notification.object;
}

Related

How to access data passed in iOS notification (simple)?

Trying to get one ViewController to communicate with another through standard Cocoa Notifications.
Wrote a simple test case. In my initial VC I add the following to viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector: #selector(mesageReceived:)
name:#"test.channel.pw" object:nil];
I add the following method:
- (void)mesageReceived:(NSNotification *)notif
{
NSString *text = (NSString *)notif;
}
I then segue to a VC which has the following added to its viewDidLoad:
NSString *test = #"someText";
[[NSNotificationCenter defaultCenter]
postNotificationName:#"test.channel.pw" object:test];
When I run it, the notification works - the messageReceived method is called - but the value of text is "test.channel.pw", not "someText" as I expected.
What is going on here, and what is the correct syntax for passing a reference to a class instance using notifications?
You need to pass your data using userInfo dictionary.
Change the notification passing code like:
[[NSNotificationCenter defaultCenter] postNotificationName:#"test.channel.pw" object:nil userInfo:[NSDictionary dictionaryWithObject:#"someText" forKey:#"dataKey"]];
And change the receiver method like:
- (void)mesageReceived:(NSNotification *)notif
{
NSString *text = [[notif userInfo] objectForKey:#"dataKey"];
}
Try NSString *text = (NSString *)[notif object];.
By this
-(void)someMethod{
NSDictionary *postDict = #{#"Key":[NSNumber numberWithFloat:17.0]};
[[NSNotificationCenter defaultCenter]postNotificationName:#"myNotification" object:postDict];
}
Some other class
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter]postNotificationName:#"myNotification" object:nil userInfo:postDict];
}
-(void)valueForNotification:(NSNotification *)notification{
NSDictionary *dict = [notification userInfo];
NSLog(#"%#",[dict objectForKey:#"Key"]); //prints out 17.0
}
You need to pass only NSDictionary object in NSnotificationCenter. Through NSDictionary you can pass any data and then you need to parse once received.

NSNotificationCenter defaultCenter iOS 8. Notification is not being delivered to one of observers

Prior iOS 8 all works fine. The problem is:
I have two observers in different classes:
class1:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishParseUser:)
name:USERS_LOADED_NOTIFICATION_ID object:nil];
class2:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didFinishParseUser:)
name:USERS_LOADED_NOTIFICATION_ID object:nil];
and notification is posted in some other place:
[FBRequestConnection startWithGraphPath:#"me/friends?fields=id,first_name,last_name,picture.type(small)" completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
[[NSNotificationCenter defaultCenter] postNotificationName:USERS_LOADED_NOTIFICATION_ID object:nil userInfo:[NSDictionary dictionaryWithObjectsAndKeys: currentUser, #"user", friends, #"friends", nil]];
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
addObserver method is called for both of mentioned classes, however notification is being delivered just to one observer. If I delete this observer(which receives the notification), then another one receives the notification.
Prior to iOS 8 both observers receive the notification.
Can you, please, help me with this issue?
Found answer.
There is another way in iOS 8 to register for receiving remote notifications. I get nil for device token and app break on line:
NSDictionary *item = #{UID_ID : sCurrentUserId, #"deviceToken": appDelegate.deviceToken, #"handle": #"", #"friends": friends};
and second observer never receives notification.
You need to register your NSNotifications to work on iOS 8 and later but don't need to register if your iOS version is less than iOS 8.
Use Following Code
NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ([[vComp objectAtIndex:0] intValue] >= 8) {
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationActivationModeBackground categories:nil]];
}
happy Coding

How to get a non null userInfo after the first time to my #selector(method)

I have a code like the following:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemPlayEnded:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:AVPlayerItemDidPlayToEndTimeNotification object:nil userInfo:userInfo];
In the selector method:
- (void)itemPlayEnded:(NSNotification *)notification
{
NSLog(#"Entered itemPlayEnded");
AVPlayerItem *p = [notification object];
NSLog(#"userinfo description %#",[[notification userInfo] description]);
}
The first time the itemPlayEnded is accessed the userInfo is non-null. After the first time the value is null.
Can anybody tell me why this is happening? Why null value for userInfo after the first time?
EDIT:
I need to clarify what is happening. I also updated my Notification code to use the lastItem which is a AVPlayerItem.
queuePlayer = [[AVQueuePlayer alloc] init];
NSDictionary *userInfo = #{#"tones": copyoftones};
for (NSString *playThis in listOfTonesToBePlayed) {
NSString *soundPath =[[NSBundle mainBundle] pathForResource:playThis ofType:#"mp3"];
NSURL *soundURL = [NSURL fileURLWithPath:soundPath];
AVPlayerItem *thePlayerItemA = [[AVPlayerItem alloc] initWithURL:soundURL];
lastItem = thePlayerItemA;
[queuePlayer insertItem:thePlayerItemA afterItem:nil];
}
queuePlayer.actionAtItemEnd = AVPlayerActionAtItemEndAdvance;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemPlayEnded:) name:AVPlayerItemDidPlayToEndTimeNotification object:lastItem];
[[NSNotificationCenter defaultCenter] postNotificationName:AVPlayerItemDidPlayToEndTimeNotification object:lastItem userInfo:userInfo];
[queuePlayer play];
What happens.
before the queuePlayer is able to play a tone the itemPlayEnded is entered along with the Dictionary non nil
Next the list of tones are played
The itemPlayEnded is re-entered with the Dictionary nil.
I wanted to use code to reset the Notification inside of the itemPlayEnded method with something like the following (p is a AVPlayerItem which is the lastItem from the code with the Notification):
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:p];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemPlayEnded:) name:AVPlayerItemDidPlayToEndTimeNotification object:p];
[[NSNotificationCenter defaultCenter] postNotificationName:AVPlayerItemDidPlayToEndTimeNotification object:p userInfo:userInfo];
[queuePlayer play];
But then the itemPlayEnded method is re-entered in a never-ending loop without playing the player. A race condition.
Any suggestions?
EDIT 2:
I have determined that the offending code is:
[[NSNotificationCenter defaultCenter] postNotificationName:AVPlayerItemDidPlayToEndTimeNotification object:lastItem userInfo:userInfo];
some how I need to set the object to use the correct sender. Not sure yet on what to put there.
EDIT 3:
What I really wanted to do was be able to loop thru the complete sequence of sounds or mp3s. I finally figured that what I was trying to do here was not going to work like I wanted it. So, I ended up using the class from https://github.com/dgiovann/AVQueuePlayerPrevious and this worked out great for me!
You are subscribing to the AVPlayerItemDidPlayToEndTimeNotification which is being posted first by yourself (with some user info) and then posted again, this time NOT by you and therefore may or may not contain any user info. Refer to the documentation to see when and why Apple will post this notification and what information you can expect with it.
https://developer.apple.com/library/mac/documentation/AVFoundation/Reference/AVPlayerItem_Class/Reference/Reference.html

Method getting called multiple times

I am using MPMoviePlayer in my project. I have registered for the movie player finish notifications and it is working good. I am displaying an error alert whenever a notification is received for movie player error. But the problem is that the error alert displays multiple times. It happens because more than one notifications are received for same error and that too at the same time. I have tried using boolean variables to control the alert display but since the notifications are received at the same time, it is not working. What approach should I apply, please suggest.
My code for notification method:
MPMovieFinishReason reason = [[[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
NSError *errorMsg = [[notification userInfo] valueForKey:#"error"];
NSString *errmsg = [errorMsg localizedDescription];
if (reason == 1 && !errorReceived){
NSError *errorMsg = [[notification userInfo] valueForKey:#"error"];
NSString *errmsg = [errorMsg localizedDescription];
[self showErrorAlert];
}
For registering notification:
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(moviePlayerDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.player];
for removing observer, in viewWillDisappear
[[NSNotificationCenter defaultCenter]removeObserver:self];
Remove the observer once you get the error
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:player];
and add the observer once you click to play .

How to transfer data ViewControllers/classes using NSNotificationCenter?

I have a table view controller that is supposed to be populated with data from an array that is encapsulated within a store class. The table needs to know how many rows are in each section via the method table:numberOfRowsInSection:. In this method, I need to return the size of the array that is inside my instance of store. I initially did this by making store a singleton, but was told this was inefficient and that using NSNotificationCenter would be better.
As far as I know, all NSNotificationCenter does is trigger methods in certain objects when another object posts a specific notification. How can I use NSNotificationCenter to send the size of the array to my table view controller?
You can do it like this:
...
// Send
[[NSNotificationCenter defaultCenter] postNotificationName: SizeOfRrrayNotification
object: [NSNumber numberWithInteger: [array count]]];
...
// Subscribe
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(sizeOfArray:)
name: SizeOfRrrayNotification
object: nil];
// Get size
- (void) sizeOfArray: (NSNotification*) notification
{
NSNumber* sizeOfArray = (NSNumber*) notification.object;
NSLog(#"size of array=%i", [sizeOfArray integerValue]);
}
Post the Notification :
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyArraySize" object: [NSNumber numberWithInteger: [myArray count]]] userInfo:nil];
Get the Notification :
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(getSizeOfArray:) name:#"MyArraySize" object:nil];
Add this method in the viewController where you are getting notification:
- (void) getSizeOfArray: (NSNotification*) notification
{
NSNumber* myArraySize = (NSNumber*) notification.object;
}
you can even send more data through "userInfo" and get that data in selector method using notification.userInfo, but remember its type is "NSDictionary"
Hope this will help you.
The method in which you are calculating the size of the array:
<------Notification sending side---------->
-(void)sizeOfArray{
int size = [myArray count];
NSMutableString *myString = [NSMutable string];
NSString *str = [NSString stringwithFormat:#"%d",size];
[myString apprndString:str];
//It is to be noted that NSNotification always uses NSobject hence the creation of mystring,instead of just passing size
[[NSNotificationCenter defaultCenter] postNotificationName:#"GetSizeOfArray" object:myString];
}
Now once you have posted a notification,add this to the viewDidLoad method of the controller where you are sending the data
<------Notification receiving side---------->
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(get_notified:) name:#"GetSizeOfArray" object:nil];
//The selector method should always have a notification object as its argument
[super viewDidLoad];
}
- (void)get_notified:(NSNotification *)notif {
//This method has notification object in its argument
if([[notif name] isEqualToString:#"GetSizeOfArray"]){
NSString *temp = [notif object];
int size = [temp int value];
//Data is passed.
[self.tableView reloadData]; //If its necessary
}
}
Hope this helps.

Resources