In my AppDelegate, I present a ViewController if the user types in my custom url scheme. It works as my ViewController is presented. However, I need to detect if my ViewController was pushed from App delegate. What is the best method or course of action to do this? I only want to detect if it comes from AppDelegate and no where else.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
ViewController *controller = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
EDIT:To clarify what I am trying to do better, when appdelegate presents my viewcontroller I need to be able to detect inside my viewcontroller that it appeared because of the method inside app delegate. So kind of like this
ViewController
-(void) ViewDidLoad{
if (this controller was presented from App delegate){
do this
}
else{
do nothing
}
Do it simply like this :
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
ViewController *controller = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
// here you know that your controller is pushed from the AppDelegate, then you can do other things just after the push
[controller callControllerPublicMethod];
}
And when you push it in an other controller, simply do not do anything.
Why not just write your own custom initializer method in the ViewController and when called from the app delegate set a parameter to true, and everywhere else set it to false.
Related
I've got an app that is a list of itens in a table view and displays a detail view controller to every item on the table view. It also implements MMDrawerController (root view controller) as a side menu with storyboard.
I'm deep linking my app and using application open URL source application annotation method from App Delegate to handle it. So, I want to push a detail view controller from this method using MMDrawerController and I'm having some trouble.
Have a look in some code:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
DetalheRestauranteViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"detalheRest"];
MMDrawerController* drawerController = (MMDrawerController *)self.window.rootViewController;
// If I use this nothing happens
[drawerController.centerViewController.navigationController pushViewController:vc animated:YES];
// If I use this nothing happens
[((MMDrawerController *)self.window.rootViewController).centerViewController.navigationController pushViewController:vc animated:YES];
// If I use this I got the unrecognized selector error
[(UINavigationController*)self.window.rootViewController pushViewController:vc animated:NO];
return YES;
}
Can someone help me with this?
I have found that with deep linking and the new iOS9 menu shortcuts that a small delay is often needed to display or manipulate UI Components.
I would try moving all of your UI/MMDrawer code to its own method. Then when openURL is called in your app delegate, call your new method on a delay.
So in ObjC it would look something like this:
[self performSelector:#selector(showDetailView) withObject:nil afterDelay:0.3];
do you solve this problem?
I tried many times. Finally I found it works fine for me today:
[((UINavigationController *)((MMDrawerController *)self.window.rootViewController).centerViewController) pushViewController:viewController animated:YES];
or
MMDrawerController *mvc = (MMDrawerController *)self.window.rootViewController;
UINavigationController *nvc = (UINavigationController *)mvc.centerViewController;
[nvc pushViewController:vc animated:YES];
These two kinds of writing are the same.
Here vc is one DetalheRestauranteViewController instance.
I'm struggling to prefill a textfield when I launch the app with my url scheme. When the app is launched without already being in memory, the value is not being set (or I think overruled by viewDidLoad or similar).
The boiled down path I'm taking looks like this:
// AppDelegate.m
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
UINavigationController *nav = (UINavigationController *)[[application keyWindow] rootViewController];
MainViewController *main = (MainViewController *)[nav topViewController];
[main setLabelText:#"this should be shown on screen"];
return YES;
}
With a ViewController sitting in a UINavigationController
// MainViewController.m
#interface MainViewController ()
#property (weak, nonatomic) IBOutlet UILabel *someLabel;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.someLabel.text = #"this is actually shown on screen";
}
- (void)setLabelText:(NSString *)text
{
self.someLabel.text = text;
}
#end
So the label shows "this is actually shown on screen", not the text I set in AppDelegate. When setting breakpoints its fairly obvious why, I think, because viewDidLoad is called after setLabelText.
Is there a more robust path to prefilling text fields from a custom url scheme I'm missing?
Try this:
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
UINavigationController *nav = (UINavigationController *)[[application keyWindow] rootViewController];
MainViewController *main = (MainViewController *)[nav topViewController];
main.view;
[main setLabelText:#"this should be shown on screen"];
return YES;
}
The view is lazy loaded so it will load the first time it is needed.
The reason for this is that setLabelText: is called from the app delegate prior to the view controller's viewDidLoad method being called. What you'll need to do is keep a copy of the string in a property on the view controller then set that on the the label in viewDidLoad:
Header:
#interface MainViewController
#property (nonatomic, copy) NSString *stringToSet;
#end
Implementation:
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
if (self.stringToSet) {
self.someLabel.text = self.stringToSet;
} else {
self.someLabel.text = #"Some default string";
}
}
#end
App Delegate:
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
UINavigationController *nav = (UINavigationController *)[[application keyWindow] rootViewController];
MainViewController *main = (MainViewController *)[nav topViewController];
[main setStringToSet:#"this should be shown on screen"];
return YES;
}
I want to access to an IBOutlet of my first Viewcontroller by AppDelegate class. My project is based with a storyboard and there isn't the reference with the first Viewcontroller.
What's the to do it?
I know that I should set this IBOutlet as a property in first Viewcontroller, but in AppDelegate? How I can access to it?
Thanks
You can access your rootViewController from your app's delegate with :
self.window.rootViewController
Example :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MyVCClass *firstVC = (MyVCClass*)self.window.rootViewController;
[firstVC someMethod];
}
Careful, your ViewController may not have been yet loaded / initiated.
Because you don't set the rootViewController for your app's UIWindow, then doing
[[UIApplication sharedApplication].keyWindow rootViewController] will give you nil.
If you use storyboards for your navigation then simply you can do this to get the rootViewController
UIViewController *vc = [self.navigationController.viewControllers objectAtIndex:0];
First import your ViewController in AppDelegate.m like this :
#import "YourViewController"
Then in AppDelegate.m place the below code
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
YourViewController * view = [[YourViewController alloc]init];
self.window.rootViewController = view;
}
I would like to open a specific UIViewController depending on an id I get from a URL scheme.
For exemple myapp://news/285 would open the UIViewController "news" displaying this specific one.
I get notified here :
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)source
annotation:(id)annotation
{
if ([[url scheme] isEqualToString:#"myapp"]) {
NSString *urlString = url.absoluteString;
...
return YES;
}
return NO;
}
But how am I supposed to push the UIViewController ? I can't access to the navigation controller from here.
(I was thinking about sending a notification with NSNotficationCenter to my home page with the id, and pushing the UIViewController from there. What do you think ?)
Thx
You know you view setup. So when you rootViewController is a UINavigationController then you can just use:
UINavigationController *navCon = (UINavigationController*)self.window.rootViewController;
[navCon pushViewController:myPushedVC animated:NO];
If not then maybe it is easier to go with the Notification approach
You could achieve that sending a notification through NSNotificationCenter. Your view controller could catch that notification and push the other view controller.
If you are using a Tab bar, then use following code.
UINavigationController *navigationController = (UINavigationController *) tabBar_Controller.selectedViewController;
you can set the selected view controller as per your requirement.
If you are not using a tabbar
UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;
Now you can push to any view.
My App has a multiple UIViewControllers that can be displayed by the user at any time.
The App can be also be started with a document (for example, an Attachment for mail App).
The scenario is the following:
- user starts the App and navigates inside the Application
- user puts the App in Background mode and he goes to Mail App
- From Mail App the user selects a mail with an Attachment and opens the Attachment with my App
- my App will enter in foreground and I would like to display the Attachment in a specific View Controller.
- When the user has finished with the Attachment, he should be able to return to the previous state in the App (before attachment was opened).
I have overloaded the following methods from UIApplicationDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
- (void)applicationDidBecomeActive:(UIApplication *)application
Using these methods I'm able to find if there's a document to be displayed and if my App was already started or not.
My issue is to push the specific ViewController.
Below is an extract of my code to push the ViewController but nothing happen, any idea? How can I find the active ViewController in my App?
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"applicationDidBecomeActive");
if (_navigationCell != Nil)
{
if ([DataCenter sharedInstance].isAppStarting == FALSE)
{
// push a new navigation stack to display the cell from the navigation
//PushArroundMeId
UIWindow* window = [UIApplication sharedApplication].keyWindow;
UIViewController* rvc = window.rootViewController;
UIStoryboard* sb= [UIStoryboard storyboardWithName:#"MainStoryboardiPhoneApp" bundle:[NSBundle mainBundle]];
AroundMeViewController* avc = [sb instantiateViewControllerWithIdentifier:#"AroundMeViewControllerId"];
if (avc != Nil) {
[rvc presentViewController:avc animated:TRUE completion:NULL];
window.rootViewController = avc;
}
}
}
}