Perform segue on viewcontroller's startup - ios

I have a login screen and what I want to do is to detect whether the user is already logged in and eventually popup a modal.
I created a custom segue that shown the modal with no animation.
#implementation NonAnimatedSegue
-(void) perform {
[self.sourceViewController presentModalViewController:self.destinationViewController animated:NO];
}
The thing is that calling this segue from viewDidLoad or viewWillAppear takes no effect. If I call it from viewDidAppear, the login screen flicks for a while before the modal opens.
Any idea how to solve this?

The way I got around this problem was to check in the application finished launching and set the root view controller as needed. Like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/*stuff*/
/*get the view controller from storyboard/nib*/
[self.window setRootViewController:CorrectViewController];
}
It wouldn't show a modal view but just show the login on launch.

Related

Tutorial screens for app

Hi I have found an awesome tutorial to show an overview of my app. how would you return back to the main app after this tutorial view has been viewed?
Here is the location of the tutorial and all the source code.
My app views are in storyboard and I have a navigationcontroller in which my rootviewcontroller is held.
I'm hoping to return to the rootviewcontroller of the navigation controller after the last page of the tutorial view is displayed.
Thank you if you can help.
Here is my storyboard:
The code I used to load the tutorial is this in AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/* This loads up the xib but I can't get back to the storyboard rootViewController */
if (tutorialHasBeenSeen == false) {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.appViewController = [[APPViewController alloc] initWithNibName:#"APPViewController" bundle:nil];
self.window.rootViewController = self.appViewController;
[self.window makeKeyAndVisible];
tutorialHasBeenSeen =TRUE;
}
return YES;
}
Would I try to pop to the rootView in the AppViewController.m in the method:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger index = [(APPChildViewController *)viewController index];
index++;
if (index == 5) {
return nil;
}
return [self viewControllerAtIndex:index];
}
Have you tried using
[self.navigationController popToRootViewControllerAnimated:YES];
EDIT
Now that I see what you are trying to do, I would recommend changing your approach:
Instead of choosing if you should present the Tutorial in the didFinishLaunchingWithOptions method in the application delegate, why don't you always start on your application's First view controller, and here determine if the user should be displayed with a Tutorial or not, in that way you can invoke the Tutorial view controller inside your First view controller in your established navigation way of displaying hierarchical content.
The reason that you can't go from Tutorial to your First view controller is because you are assigning the Tutorial as your window view controller directly from the app delegate. So there is no way of going 'back' from Tutorial to your First view controller, to fix this I can think on two options,
At a desired moment change the window view controller of your application to be your First view controller instead of the already assigned Tutorial view controller. Which, as you may be guessing, is a tricky and just not clean way of doing this.
Set up a proper navigation hierarchy in your app, so First view controller should present your Tutorial view controller. And after, at a desired moment you simply dismiss or pop your Tutorial and get back to your First view controller.
As a conclusion,
1.Don't present your Tutorial from the AppDelegate, so leave the following method clean or as necessary but to perform other actions.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}
2.From the view controller that will be your First view controller, invoke your Tutorial using segues or by code applying your desired logic for determining when a user should see the tutorial. If done properly when the app starts and the Tutorial appears it will be invisible that you are first displaying the First view controller
3.From your Tutorial view controller and at the desired moment dismiss or pop (will depend on your navigation) your view controller so you can go back to the First view controller

Can't call View Controller method from app delegate

I'm trying to build the sample app from facebook iOS SDK but I'm using storyboards so it's a little different.
I'm doing this check in my AppDelegate.m application didFinishLaunchingWithOptions:
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
// To-do, show logged in view
} else {
// No, display the login page.
[self showLoginView];
}
return YES;
I've created a segue from my main ViewController to a navigation controller. The segue works fine if I trigger it using a button in my ViewController view, but I can't call that method from my AppDelegate.
The name of the method(that performs the segue) is -displayLoginView but I canĀ“t find a way to point to the particular instance of my ViewController that is active at launch.
Any ideas?
Your UIApplicationDelegate is not a view controller so it cannot initiate any segues.
You probably want to call self.window.rootViewController to get the viewcontroller in question but it might be easier to put that code in your viewController's viewDidAppear or viewWillAppear method instead of the app delegate.

iOS: Pushing a view controller with animation only works once

I am creating an iPhone client for one of my apps that has an API. I am using the GTMOAuth2 library for authentication. The library takes care of opening a web view for me with the correct url. However I have to push the view controller myself. Let me show you some code to make things more clear:
- (void)signInWithCatapult
{
[self signOut];
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:[_account catapultAuthenticaiton]
authorizationURL:[NSURL URLWithString:kCatapultAuthURL]
keychainItemName:kCatapultKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[self.navigationController pushViewController:viewController animated:YES];
}
I have a "plus"/"add" button that I add to the view dynamically and that points to that method:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(signInWithCatapult)];
When I press the "add" button, what is supposed to happen is to open the web view with an animation, and then add an account to the accounts instance variable which populates the table view. This works fine if I add one account, but as soon as I try to add a second account, the screen goes black and two errors appear in the console:
nested pop animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
The only way that I found to avoid this problem was to disable animations when pushing the view controller.
What am I doing wrong please?
Typical situations
You push or pop controllers inside viewWillAppear: or similar methods.
You override viewWillAppear: (or similar methods) but you are not calling [super viewWillAppear:].
You are starting two animations at the same time, e.g. running an animated pop and then immediately running an animated push. The animations then collide. In this case, using [UINavigationController setViewControllers:animated:] must be used.
Have you tried the following for dismissing once you're in?
[self dismissViewControllerAnimated:YES completion:nil];
I got the nested pop animation can result in corrupted navigation bar message when I was trying to pop a view controller before it had appeared. Override viewDidAppear to set a flag in your UIViewController subclass indicating that the view has appeared (remember to call [super viewDidAppear] as well). Test that flag before you pop the controller. If the view hasn't appeared yet, you may want to set another flag indicating that you need to immediately pop the view controller, from within viewDidAppear, as soon as it has appeared. Like so:
#interface MyViewController : UIViewController {
bool didAppear, needToPop;
}
...and in the #implementation...
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
didAppear = YES;
if (needToPop)
[self.navigationController popViewControllerAnimated:YES];
}
- (void)myCrucialBackgroundTask {
// this task was presumably initiated when view was created or loaded....
...
if (myTaskFailed) { // o noes!
if (didAppear)
[self.navigationController popViewControllerAnimated:YES];
else
needToPop = YES;
}
}
The duplicated popViewControllerAnimated call is a bit ugly, but the only way I could get this to work in my currently-tired state.

iOS Storyboard Switch to a View that has no segue on AppDelegate

I have a one time agreement view that will only show up when user launches app first time.
I use storyboard IOS 5.1 and My rootview is a navigationviewcontroller. My agreement view has no connection with navigation controoler I just want to present a modalview pop up then dismiss the view:
I use following code but it doesn't do anything app just continues and launches navigationviewcontroller I put flags, yes app enters the if statement. :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if(login==ok){
UIStoryboard *storyboard = [UIApplication sharedApplication].delegate.window.rootViewController.storyboard;
UIViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:#"AgreementViewController"];
[self.window.rootViewController presentModalViewController:loginController animated:YES];
}
return YES;
}
How can I switch a viewcontroller that has no connection to storyboard and dismiss it?
In the app I've been working on last weekend I had a similar situation. I wanted to show a seperate storyboard the first time for a guided setup.
My code looked pretty much the same as yours and it gave me a warning when I was debugging it.
This was because of the fact that the rootViewController I was trying to present my one-time ViewController on, isn't visible at this point in the app.
So, instead of presenting my one-time view controller "on" the rootViewController, I decided to set my one-time view controller as the rootViewController.
In your case it would be something like:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if(login == ok) {
UIStoryboard *storyboard = [UIApplication sharedApplication].delegate.window.rootViewController.storyboard;
UIViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:#"AgreementViewController"];
[self.window setRootViewController:loginController];
}
return YES;
}
To dismiss it, you could probably add a segue from your one-time view controller to your first view controller or you could use code similar to the one in your question.
Another approach would be to do the check and view switching in your first "normal" view's viewDidAppear, instead of in the AppDelegate.
Hopefully this will point you in the right direction.

iOS 5 Storyboard with Sign In Overlay (iOS 5.1; Xcode 4.3.3)?

I'm trying to create an iOS (iPhone specific) app where users have to authenticate before accessing the rest of the app. I'm using a Storyboard for the main application which looks like this (broken up into separate lines):
(1) -> NavigationController
(2) -(o-o)-> OfficesViewController
(3) -[<-]-> OfficeViewController
I also have a separate XIB file called ScanOverlayViewController which gets programmatically pushed by the OfficeViewController when a user presses on a button. Not sure if it's proper to have Storyboards and XIBs mixed in like this, but it's been working so far.
Anyway, back on topic, I want to put an authentication screen infront of the NavigaitonController, but I'm not sure how.
I've tried placing an unlinked view in the Storyboard and setting it as the initial view. I then placed a hidden button and made a segue to the NavigationController. In code I tried having the controller perform the segue but the seque wasn't actually being performed even though the view had appeared properly.
I then tried to make the authentication view it's own separate XIB and initializing the controller in the app delegate and setting its view as a sub view of the app delegate. That just resulted in the app going directly to the OfficesViewController view as if I hadn't done anything.
Is there a specific way of doing this properly so it works with Storyboards?
Thanks in advance!
UPDATE
Here's my current app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
AuthenticationViewController *authenticationViewController = [[AuthenticationViewController alloc] initWithNibName:#"AuthenticationViewController" bundle:nil];
if (authenticationViewController) {
NSLog(#"Should have generated %#", authenticationViewController);
};
[[[application keyWindow] rootViewController] presentModalViewController:authenticationViewController animated:YES];
return YES;
}
The controller does get allocated and initialized, but it's just not showing up.
Have the NavigaitonController as your initial view controller, then present the authentication screen modally if required. You can do this in -application:didFinishLaunchingWithOptions:.
Mixing XIB files and storyboards is fine, storyboards get turned into XIB (or nib) files anyway, they just have some extra meta data. Mix and match as makes sense.
E.g.:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([self needsAuthentication])
{
dispatch_async(dispatch_get_main_queue(), ^{
AuthVC *authVC = [[AuthVC alloc] init];
[[UIWindow keyWindow].rootViewController presentModalViewController:authVC animated:YES];
});
}
// anything else
return YES;
}

Resources