Call Selector method from another Class - NSNotificationCenter - iphone

I would like to know how I can call the selector which is in another class when notification is posted.I am on tabbarcontroller.
The FirstViewController, SecondViewController are tab bar items
Inside `FirstViewController` I have the following
-(void)viewdidload
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(productPurchased:) name:kProductPurchasedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector: #selector(productPurchaseFailed:) name:kProductPurchaseFailedNotification object: nil];
}
- (void)productPurchased:(NSNotification *)notification {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
NSString *productIdentifier = (NSString *) notification.object;
NSLog(#"Purchased: %#", productIdentifier);
[appDelegate.myDownloadablePoemsArray addObject:productIdentifier];
[self.tabBarController setSelectedIndex:3];
}
- (void)productPurchaseFailed:(NSNotification *)notification {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
SKPaymentTransaction * transaction = (SKPaymentTransaction *) notification.object;
if (transaction.error.code != SKErrorPaymentCancelled) {
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Error!"
message:transaction.error.localizedDescription
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil] autorelease];
[alert show];
}
}
The above code is working fine. Now what the issue is, I want to call the same selector method from my another view say for example I have a view controller named SecondViewController, in that I am adding the same notification observer.
but the selector method is not called in the FirstViewController.
Inside SecondViewController I have the following
-(void)viewdidload
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(productPurchased:) name:kProductPurchasedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector: #selector(productPurchaseFailed:) name:kProductPurchaseFailedNotification object: nil];
}
But I want to call the selecor methods from FirstViewController;
Please let me know , is that possible ? And how can I do that?
Thanks a lot

in the SecondViewController change the self as observer to the pointer of the FirstViewController, because the instance of FirsViewController has the methods.
inside SecondViewController.m you must use these lines:
- (void)viewdidload {
[[NSNotificationCenter defaultCenter] addObserver:firstViewController selector:#selector(productPurchased:) name:kProductPurchasedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:firstViewController selector: #selector(productPurchaseFailed:) name:kProductPurchaseFailedNotification object: nil];
}
BUT! AND THIS IS THE POINT.
if the FirstViewController is already a valid and loaded view controller in the memory with the methods as you've mentioned above, and it is an observer already for these notifications in the NSNotificatioCenter, you don't need to add again it to the NSNotificationCenter because the FirstViewController can receive and will receive the desired notification still. (it is just not shown, because an other view controller covers it.)
if the FirstViewController is not exists yet when the SecondViewController is, you cannot reach any instance method called from an another class because the FirstViewController was not instantiated before, and you cannot add it to the NSNotificationCenter as well.
CONCLUSION
it would be better to isolate the purchase callbacks into a third class what you can use for every independent view controller, according to the spirit of the OOP and MVC.

If your view controllers are the roots of tab-bar controllers, once they are loaded the first time, they stay around unless manually replaced.
Thus, when you install the notification handler in the first controller, unless you remove the notification handler, it will still get them, even when the second controller is onscreen.
Now, it may get unloaded due to memory pressure, or by the custom tab-bar-controller code. However, it's highly unusual for a tab-bar controller to deallocate one of its view controllers, so your installed notification handlers will be around until you cancel them.
In fact, if both view controllers register for the notifications, then they will both get them.
You are registering in viewDidLoad so the first one will get registered immediately, as it will be loaded and displayed as the initial controller. It will continue to receive those notifications.
When the second one loads, it will also register. Now both view controllers are receiving the notifications. When you go back to the first view controller, they will both still be getting the notifications.

Related

Present another View Controller from SkScene

I'm trying to present another viewController from my "SkScene".
This is my main viewController(tuViewController)
Code:
-(void) openTweetSheet{
FacebookLikeViewDemoViewController *ctrl = [[FacebookLikeViewDemoViewController alloc] initWithNibName:#"FacebookLikeViewDemoViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
This is my "SkScene":
tuViewController *viewController = [[tuViewController alloc]init];
[viewController openTweetSheet];
And the viewController which i want to present is FacebookLikeViewDemoViewController and i need to have way back to "SkScene".
And i got sigabrt error, i tried few ways to present viewController but always with failure, one time i got swap to viewController but it was entirely black. I read a lot how to perform that, but i personally can't figure out. I appreciate your help.
I tried too with Notification Center.
Main viewController
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(goToGameOverViewController:)
name:#"GoToGameOverViewController"
object:nil];
-(void)goToGameOverViewController:(NSNotification *) notification {
FacebookLikeViewDemoViewController *helpVC = [[FacebookLikeViewDemoViewController alloc]initWithNibName:#"HelpViewController" bundle:nil];
UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootVC presentViewController:helpVC animated:YES completion:nil];
}
SkScene
[[NSNotificationCenter defaultCenter]
postNotificationName:#"GoToGameOverViewController" object:self];
But i got the same error. I prefer to figure out why the way with notification won't work.
I assume by your question that you are looking to do some social media posting.
You can either pass a reference for your View Controller to your SKScene or you can use NSNotificationCenter instead. I prefer to use the latter.
First make sure you have added the Social.framework to your project.
Import the social framework into your View Controller #import <Social/Social.h>
Then in your View Controller's viewDidLoad method add this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(createTweet:)
name:#"CreateTweet"
object:nil];
Next add this method to your View Controller:
-(void)createTweet:(NSNotification *)notification
{
NSDictionary *tweetData = [notification userInfo];
NSString *tweetText = (NSString *)[tweetData objectForKey:#"tweetText"];
NSLog(#"%#",tweetText);
// build your tweet, facebook, etc...
SLComposeViewController *mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
At the appropriate location in your SKScene, (won game, lost game, etc...) add this code:
NSString *tweetText = #"I just beat the last level.";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:tweetText forKey:#"tweetText"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CreateTweet" object:self userInfo:userInfo];
The above code sends a NSNotification, with text, which your View Controller will pick up and execute the specified method (which is createTweet in the above example).

Open View from didReceiveRemoteNotification

I have this question asked few times and I have tried a few different methods but have not been successful.
The latest method I have tried is as followed :
I included the ViewController that I wanted to show. I then put this code in the didReceiveRemoteNotification method.
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
// [self.window.rootViewController presentViewController:pvc animated:YES completion:nil];
[(UINavigationController *)self.window.rootViewController pushViewController:pvc animated:NO];
This did not work. I think the problem I may be having is that my initial view is not a navigation controller like a lot of the examples show.
This is a picture of my story board> The VC that I want to send the user to is the car finder (bottom right)
Can someone explain to me what I might be doing wrong?
You could use basically postNotification when you receive the Remote Notification
for exmaple in your didReceiveRemoteNotification post notification like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
now in your FirstViewController's you can register the FirstViewController for this notification like this
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushNotificationReceived) name:#"pushNotification" object:nil];
and in your method
-(void)pushNotificationReceived{
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
[self presentViewController:pvc animated:YES completion:nil];
}
don't forget to remove the observer from notification in your dealloc method
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I think the simplest solution would be to show the CarFinderViewController as a modal view instead of trying to push it to a navigation controller which may or may not be visible at the time.
Another important point to avoid further inconsistencies I'd recommend you instantiate your CarFinderViewController from the storyboard instead of directly through the class methods.
Something like:
UIViewController * vc = self.window.rootViewController;
// You need to set the identifier from the Interface
// Builder for the following line to work
CarFinderViewController *pvc = [vc.storyboard instantiateViewControllerWithIdentifier:#"CarFinderViewController"];
[vc presentViewController:pvc animated:YES completion:nil];

dismissModalViewControllerAnimated from another view controller class

I do have two ViewController class, one firstviewController other secondViewController in first viewcontroller i call this [self dimissModalViewControllerAnimation:NO];
to dimiss the view! now i need to dimiss the same view from another secondViewController class.
So do i need to call super in that!
[super dismissModalViewControllerAnimated:NO];
Or Do i need to create any protocol for dismissing the view! from another secondViewController class.
Can any guide me with this issue.
you can register a notification in firstViewController's viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"MyNotification" object:nil];
Add the event handler in firstViewController
- (void)handleNotification:(NSNotification*)note {
[self dismissModalViewControllerAnimated:NO];
}
Then you can trigger the event in secondViewController
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:nil ];
You should only be using super when you're overloading a method definition, e.g.:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Login / Signup";
}
Typically, if you're trying to tell one view to do something from another view, delegates are your friend. You could create a weak delegate variable to hold a reference to the view controller to be dismissed, and call [delegate dismissModalViewControllerAnimated:NO];

Present view when local notification is received

With iOS 5 and storyboarding, what is the best way to present a view when the user enters the app after having received a localnotification?
I have read that using the NSNotificationCenter is the way to do it but is that also so with storyboarding and segues?
This is exactly how I implemented it. In the AppDelegate's didFinishLaunchingWithOptions: method, I did the following:
UILocalNotification *notification =
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
[self application:application didReceiveLocalNotification:notification];
I did this so that I could keep logic in a single place. In the didreceiveLocalNotification: method, I then used the NSNotificationCenter:
// Let another view handle the display
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:#"SHOW_VERSE"
object:self
userInfo:notification.userInfo];
The view that handles the display is the first UIViewController for the Storyboard. In that class, in the viewDidLoad method:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedLocalNotification:)
name:#"SHOW_VERSE"
object:nil];
This works very well for me. Hope it helps.

iPhone - Launching selectors from a different class

I'd like to reload a table view which is in another class called "WriteIt_MobileAppDelegate" from one of my other classes which is called "Properties". I've tried to do this via the NSNotificationCenter class - the log gets called but the table is never updated.
Properties.h:
[[NSNotificationCenter defaultCenter] postNotificationName:#"NameChanged"
object:[WriteIt_MobileAppDelegate class]
userInfo:nil];
WriteIt_MobileAppDelegate.m
-(void)awakeFromNib {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadItProperties:)
name:#"NameChanged" object:self];
}
- (void) reloadItProperties: (NSNotification *)notification {
NSLog(#"Reloading Data"); //this gets called
[[self navigationController] dismissModalViewControllerAnimated:YES];
[self.navigationController popToRootViewControllerAnimated:YES];
[self.tblSimpleTable reloadData];
[self.tblSimpleTable reloadSectionIndexTitles];
// but the rest doesn't
}
What am I doing wrong here?
Seems like you are using the object parameter wrong:
addObserver:selector:name:object:
notificationSender
The object whose
notifications the observer wants to
receive;
that is, only notifications
sent by this sender are delivered to
the observer. If you pass nil, the
notification center doesn’t use a
notification’s sender to decide
whether to deliver it to the observer.