I have the following code within my AppDelegate. It is used during checks for In App Purchase expiry, and if a subscription is expiring, will present a popup for the user to choose to renew, and if they do, it will push the view controller for the In App Purchases onto the stack.
I would like to shift the code out of AppDelegate, and into its own NSObject class (just for tidiness). However, how do I call push the View Controller from another class?
self.window.rootViewController doesn't exist on the NSObject class, so of course won't function.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UICollectionViewController *ivc = (UICollectionViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"IAPViewController"];
[navigationController pushViewController:ivc animated:YES];
In your NSObject class, when you want to push a vc, post a notification via NSNotificationCenter:
[[NSNotificationCenter defaultCenter] postNotificationWithName:#"PushMyViewControllerNote" object:nil];
And in AppDelegate.m register observer:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handlePushVCNotification:)
name:#"PushMyViewControllerNote"
object:nil];
//...
return YES;
}
//...
- (void)handlePushVCNotification:(NSNotification *)note
{
// First you must find currently visible view controller
// for how to do it, find it yourself :)
// but you can check https://gist.github.com/snikch/3661188
UIViewController *visibleVC = [self findVisibleVC];
UINavigationController *nc = visibleVC.navigationController;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UICollectionViewController *ivc = (UICollectionViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"IAPViewController"];
[nc pushViewController:ivc animated:YES];
}
What you should do is create a separate class that inherits from NSObject. Call it something like AppPurchase. Then, import your AppPurchase class into your app delegate. As for pushing the view controller, that code should be separate from your AppPurchase class.
The AppPurchase class is part of your Model, and should not be responsible for pushing view controllers around. If data changes in your AppPurchase instance, then the controller can take some action and alter your View.
You should look into learning more about MVC or Model-View-Controller.
Related
i had setup an redirect after user click the push notification and it did worked. However the app is redirect to the View Controller without navigation bar and bottom toolbar.. Below are my redirect code : -
// Did receive notification method here...
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo NS_AVAILABLE_IOS(3_0)
{
NSLog(#"user info1 is %#",userInfo);
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATION_RECIEVED"
object:nil
userInfo:nil];
UIStoryboard *mainsboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainsboard instantiateViewControllerWithIdentifier:#"notice"];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
This screenshot showing the notice storyboard properties
This screenshot showing the top navigation item properties
I think I understand the question to mean that you expect the view controller to appear in the context of a navigation controller that you have configured in storyboard. In that case, you'll need to do a little more to set things up:
find the navigation controller in your storyboard that contains the one with the "notice" ID, and give it a storyboard ID, too -- maybe something like "noticeNavigationController"
upon receiving the notification, build navigation controller from storyboard, too, and set it's root with the "notice" view controller that you know how to build...
// as you have it
UIStoryboard *mainsboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainsboard instantiateViewControllerWithIdentifier:#"notice"];
// but now build a navigation controller, too
UINavigationController *navVC = [mainsboard instantiateViewControllerWithIdentifier:#"noticeNavigationController"];
// make your vc the root
navVC.viewControllers = #[ vc ];
// and present** that navigation controller
[self.window.rootViewController presentViewController: navVC animated:YES completion:nil];
**Note, unless you're doing a presentation intentionally for some reason, it's more commonplace to just set the app's rootViewController to the navVC, rather than present it.
I want to reinitialize my app from top view controller problematically. I want my app reload the views from start.
I have tried this in applicationWillEnterForeground method:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
ActivityController *destViewController = (ActivityController *)[storyboard instantiateViewControllerWithIdentifier:#"ActivityView"];
[self.navigationController pushViewController:destViewController animated:YES];
But it doesn't work.
If you don't want your app to be running in the background, you can set UIApplicationExitsOnSuspend to true in your app's Info.plist
applicationDidEnterBackground and applicationWillEnterForeground,
[[NSNotificationCenter defaultCenter] postNotificationName:#"popToRoot" object:nil];
and in your rootViewController's viewDidLoad (that always appears on app launch) add this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(popToRootViewControllerAnimated) name:#"popToRoot" object:nil];
Then create a method in your rootViewController:
- (void)popToRootViewControllerAnimated
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
You should use [self.navigationController popToViewController:ActivityController animated:NO]; instead of popToRoot.
Refer this answer for more details.
I am getting notification appdelegate didReceiveRemoteNotification but i want to use this payload data in view controller how to do that?
There are a number of ways to achieve this, and the question is a little vague. Assuming that you have a view controller in your application this is active when your notification arrives, perhaps the simplest way would be to use an NSNotification to broadcast the payload from the app delegate to your interested view controller.
In your view controller:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receivedRemoteNotification:)
name:#"RemoteNotification"
object:nil];
And implement the method -receviedRemoteNotfication.
Then, in your app delegate's remote notification method:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"RemoteNotification"
object:payload];
You have to place your UITabBarController in a UINavigationController in your AppDelegate. Once you do this, then you declare the rootViewController of your application's main window a UINavigationController. Declare this in your header file of your AppDelegate:
#property (nonatomic, strong) UINavigationController * mainWindowRootViewController;
Then do this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[_window makeKeyAndVisible];
_mainWindowRootViewController = [UINavigationController new];
[self.window setRootViewController:_mainWindowRootViewController];
///code code code
[_mainWindowRootViewController setViewControllers:#[splashScreen, tabBarController] animated:TRUE];
...//code code code
return YES;
}
Now that you have your mainWindowRootViewController holding your splashScreen as the it's rootViewController and your tabBarController as the second viewcontroller on the stack, you can do this:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
UIViewController * commentsViewController = [UIViewController new];
UINavigationController * tempNAV = [[UINavigationController alloc] initWithRootViewController:commentsViewController];
[_mainWindowRootViewController presentViewController:tempNAV animated:TRUE completion:nil];
}
When you present the comments view controller, it will be presented over the entire stack of controllers including the UITabBarController and the splashScreen (if you have a splash screen). Also, to all the people who may say, "you can't present a UINavigationController with a UINavigationController", yes you can, try it for yourselves, it's amazing!
This assumes you have the comments view controller declared in the AppDelegate, if you have declared this "localNotif" somewhere else, then you can do this same presentation OVER the entire STACK of view controllers over the entire app window by using the following modifications:
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
UIViewController * commentsViewController = [UIViewController new];
UINavigationController * tempNAV = [[UINavigationController alloc] initWithRootViewController:commentsViewController];
[[(YOURAppDelegate *)[UIApplication sharedApplication].delegate mainWindowRootViewController] presentViewController:tempNAV animated:TRUE completion:nil];
}
i am developing a app that has a storyboard with 3 view controllers and app in push notification enabled. and when i receive a push notification and when i tap on notification alert it should open a second view controller from my storyboard let me show my code.
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
}
and then storyboard loads which is actually my first view controller which also have a button in it to second view controller and that is the controller i want to load. and here is the code in my first view controller.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushNotificationReceived) name:#"pushNotification" object:nil];
}
-(void)pushNotificationReceived{
NSString * storyboardName = #"DealerMainStoryboard";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"DealerBuyRequests"];
[self presentViewController:vc animated:YES completion:nil];
}
so when i receive notification with this code app crashes when i tap on notification.
You need to get some error log but check this.
UIViewController * vc =
[storyboard instantiateViewControllerWithIdentifier:#"DealerBuyRequests"];
I don't think you want to create a new UIViewController , unless you really named your controller "UIViewController".
So check again the class name of the View you want to present modally
DealerBuyRequestsViewController * vc =
[storyboard instantiateViewControllerWithIdentifier:#"DealerBuyRequests"];
Make sure the StoryBoard Id of this View controller matches DealerBuyRequests or you will get errors.
I'm trying to change the ViewController when an area in a pic is pressed.
I tried doing this :
-(void)openDrawer{
UIStoryboard *mStoryBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc =[mStoryBoard instantiateViewControllerWithIdentifier:#"DrawViewController"];
[self.navigationController pushViewController:vc animated:YES];
}
but self.navigationController does not exist, that is understandable, but I can not find a way to get a the current viewController with in the Image
I tried putting it in a different class, delegating from the viewController of the current view.
-(void) changeChangeViewToName:(NSString *)name{
UIStoryboard *mStoryBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc =[mStoryBoard instantiateViewControllerWithIdentifier:name];
[self.navigationController pushViewController:vc animated:YES];
}
This works from inside the viewController but I can't call the function from inside the Image.
Post a notification from the class (image?) that decides it wants the new view controller displayed. Listen for that notification in the existing view controller that is capable of doing the push.
Phillip Mills is right. You could also use the delegate pattern:
Create a protocol for objects that should be able to perform the desired action:
#protocol YourImageDelegate
-(void)touchUpInsideArea;
#end
Add this method to your view controller:
-(void)touchUpInsideArea {
[self openDrawer];
}
Set up your view controller to conform to the protocol:
#interface YourViewController : UIViewController
And don't forget to include your protocol in both files: the view controller class and the image class.