For iOS, Any way to know the navigation source? - ios

Any way to know the navigation source?
For example, the navigation stack has A/B/C three view controllers.
If C is popped, when B is displayed, any way to know the navigation is from C to B ?
Thanks a lot in advance.

in another simple method
first declare the UINavigationController in Appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:self.viewController];
self.window.rootViewController = nav;
[nav setNavigationBarHidden:YES];
[self.window makeKeyAndVisible];
return YES;
}
after that in your first view controller.m import the second view controller header file
#import "B.h"
in your button action
- (IBAction)butvie:(id)sender {
B*tab=[[Balloc]init];
[self.navigationController pushViewController:tab
animated:YES];
}
in C viewcontroller comes to back of B
- (IBAction)butvie:(id)sender {
[self.navigationController popViewController
animated:YES];
}

You can track this manually. You can keep a global variable in your AppDelegate class and set that variable whenever you pop a particular viewController.
UPDATE after comments:
In this case, you can use NSUserDefaults or you can post an NSNotification object from the poppedViewController. Though I am not sure, how much efficient these options are for you to use.

You can tell whether a controller appeared because it was added to the stack, or because another controller was popped off the stack using isMovingToParentViewController. If you have this code in B, it will tell you which happened:
-(void)viewDidAppear:(BOOL)animated {
if ([self isMovingToParentViewController]) {
NSLog(#"Coming from A");
}else{
NSLog(#"Coming from C");
}
}

Related

How to return to root ViewController, if the current is deeply nested?

I have a problem that my iOS app has several ViewControllers.
For example: ViewControllers named like A, B, C. A jumped to B with pushViewController, B jumped to C with presentViewController , C jumped to D with presentViewController and so on.
If the current ViewController is Z or some other ViewController, how can I jump back to A directly?
Try Below code. It will work for all cases :
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:[nameOfYourViewControllerYouWantToNavigate class]])
{
if(controller.isBeingPresented)
[controller.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
else
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
[[self navigationController] popToRootViewControllerAnimated:YES];
It will pop your viewcontroller to Root controller.
For the view controllers show by pushViewController, you can get rootViewController via [self.navigationController.viewControllers objectAtIndex:0]
Others shown by presentViewController, you can get parent view controller via self.presentingViewController
Whatever you want to go back to A ViewController from any other view controller, first you have to set that as RootViewController. If you use XIB you must set as root in app delegate didFinishLaunchWithOptions method. If you use storyboard you should set NavigationController in storyboard and set AViewController as ROOT using control+drag(mouse).
I work in a project which has lot of view controllers. It has pushViewController and PresentViewControllers also I set A asRootViewController. So I can return from any view controller to RootViewController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
AViewController *aVC = [[AViewController alloc]initWithNibName:#“AViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:aVC];
self.window.rootViewController = aVC;
[navController setNavigationBarHidden:YES];
self.window.backgroundColor = [UIColor clearColor];
[self.window makeKeyAndVisible];
return YES;
}
For going to AViewController from any other view controller
- (IBAction)actionGoBack:(id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}

Root View controller is deallocated so how do I retain it or add it to my navigation controller again

After I logout using this:
- (IBAction) logoutButtonPressed:(UIButton *)sender
{
[Users logOut];
[self.navigationController popToRootViewControllerAnimated:YES];
}
The screen goes black if I have been logged in for like 12 hours. I guess the rootview controller is deallocated.
This is how it's created in appDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
StartViewController *viewController = [[StartViewController alloc] init];
StartNavigationController *navigationController=[[StartNavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
}
How can I make startviewcontroller show again? Or whatever the root is?
When you assign self.window.rootViewController, a strong reference is created for that object and hence with ARC it would not be deallocated unless the object pointing to it was deallocated.
So your StartViewController is the rootViewController of a navigation controller. How do you add the controller where you call the poptoRootViewController?
When performing the pop, get the view controllers array of the navigation controller and make sure that your root view controller is intact.

Switching to an arbitrary view using `UINavigationController`

I have an iPhone app that uses a UINavigationController that is created as so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Create navigation controller and initialize it with the menu view controller.
navigationController = [[UINavigationController alloc] initWithRootViewController:[[MenuViewController alloc] init]];
navigationController.navigationBar.hidden = YES;
navigationController.toolbar.hidden = YES;
// Create main window and initialize it with navigation view controller.
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setRootViewController:navigationController];
[window makeKeyAndVisible];
return YES;
}
From there things usually happen in a sequence similar to the following:
Push SelectDifficultyViewController
Push GameViewController
Push GameOverViewController
Pop to root (MenuViewController)
Instead of popping to the root in step 4, how would I go about switching to a new instance of GameViewController.
I currently have the following but it just returns me to the root:
[self.navigationController popToRootViewControllerAnimated:NO];
[self.navigationController pushViewController:[[GameViewController alloc] initWithStuff:stuff] animated:NO];
As it turns out, the line [self.navigationController popToRootViewControllerAnimated:NO] will result in self.navigationController being nil, which is why the subsequent push to the navigationController does nothing. To fix this, store a local copy of the navigation controller and use that to push after popping to root. Credit for this answer comes from here:
UINavigationController popToRootViewController, and then immediately push a new view
mehinger's answer solved my problem, but I wanted to make it easier to use, so I made the following category.
UINavigationController+PopAndPush.h
#interface UINavigationController(PopAndPush)
- (void)popAndPushToViewController:(UIViewController *)controller animated:(BOOL)animated;
- (void)popAndPushToViewController:(UIViewController *)controller withCustomTransition:(CustomViewAnimationTransition)transition;
#end
UINavigationController+PopAndPush.m
#import "UINavigationController+PopAndPush.h"
#implementation UINavigationController(PopAndPush)
- (void)popAndPushToViewController:(UIViewController *)controller animated:(BOOL)animated {
[self popToRootViewControllerAnimated:NO];
[self pushViewController:controller animated:animated];
}
- (void)popAndPushToViewController:(UIViewController *)controller withCustomTransition:(CustomViewAnimationTransition)transition {
[self popToRootViewControllerAnimated:NO];
[self pushViewController:controller withCustomTransition:transition subtype:nil];
}
#end

Switch between different Views with a Navigation Controller

I'm totally new to iOS programming. I only programmed on Android so far and Objective-C is a total different and new language for me now.
What I want to do is to not use a design that I've created with the storyboard. I want to do all programmatically, since I think it will be more dynamic if I do it like this.
The problem I'm encountering is, that I want to have 3 different views. I googled a bit, and stumbled upon some stackoverflow questions. There, people suggested using a NavigationController. Okay. Now I'm trying to implement it. What I want to have is the following
A MainViewController that has 3 different views. The first view is a loginView. The second one is displaying data and the third is displaying detailed data dependent on the click of the second view.
Is a navigationcontroller corerct for this? The problem I'm having is where I tell the app that I want to start with the MainViewController and push the LoginView in it.
I have a MainViewController.h and MainViewController.m that are subclasses of UIViewController
Now, where exactly do I do this? I have the didFinishLaunchingWithOptions method right here with the following content
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
UIViewController *viewController = [[MainViewController alloc]init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navigationController pushViewController:viewController animated:NO];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
But that just crashes the app. What am I doing wrong? How do I get those three views? Am I starting completely wrong? Please help. As I said I'm new to iOS development. It's easy for me to programm on one view. I did that already, but I want thre different views! Thanks!
A MainViewController that has 3 different views. The first view is a loginView. The second one is displaying data and the third is displaying detailed data dependent on the click of the second view.
That's wrong.
You need three different view controllers, each of those will manage its own view.
Then you push one after another in the navigation controller, depending on user interaction.
Yes, Gonzalo Aune is rite, You should not push the rootviewcontroller in NavicationController.
Also , I will Suggest you to keep your first view (Login View) out of Navigation controller.
You can start with your MainViewController and based on check and conditions you can present LoginView on MainViewController using
[self presentViewController:loginViewController animated:YES completion:NULL];
And after successful login you can dismiss LoginViewController.
Remove this:
[navigationController pushViewController:viewController animated:NO];
You shouldnt push the ViewController since you told the NavigationController already that the ViewController would be the root one:
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:viewController];
use this code and if application is universion then use same code else remove the condition of ([[UIDevice currentDevice] userInterfaceIdiom]
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navController;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
{
if(result.length>0)
{
for(var i in result)
{
var ObjResult=result[i];
var content = "<div data-role='collapsible' id='set" + i + "'>";
content+="<h3>"+ObjResult.title+"<br>";
var intDate=parseInt(ObjResult['ordered date']);
content +=timestampToDate(intDate)+"</h3>"
if(isNaN(ObjResult.med_placeorderfor))
content+="<p><a>Medicle Place order for: </a>"+result[i].med_placeorderfor+"</p>";
if(isNaN(ObjResult.pres_placeorderfor)>0)
content+="<p><a>Medicle Place order for: </a>"+result[i].placeorderfor+"</p>";
if(ObjResult['order status'].length>0)
content+="<p><a>Order status: </a>"+ObjResult['order status']+"</p>";
if(ObjResult.comments.length>0)
content+="<p><a>Comments: </a>"+ObjResult.comments+"</p>";
content+="</div>";
}
$("#id_notification_list_dashboard").append( content ).collapsibleset('refresh');
$("#id_notification_list_dashboard").trigger('create');
}
else
{
$("#id_notification_list_dashboard").append("<div style=\"text-align:center\" data-role='list-divider'><h1>No data found</h1></div>").collapsibleset('refresh');
}
$('body').removeClass('ui-loading');
loadingWithMsg("hide");
}
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
navController=[[UINavigationController alloc]initWithRootViewController:self.viewController];
[navController.navigationBar setTranslucent:YES];
navController.navigationBar.tintColor = [UIColor colorWithRed:161.0f/255.0f green:18.0f/255.0f blue:6.0f/255.0f alpha:1];
self.window.rootViewController =navController ;
[self.window makeKeyAndVisible];
return YES;
}

iOS initial log in view before navigational Controller

I have been playing around with this for a couple of days and I cannot figure this out.
-> Basically I want to implement a simple login view that has a button when clicked, goes to go to the navigation controller ( in my case is "viewController" with buttons that link to mini math games which are other views).
-> Login screen should be displayed first, than navigation controller's root view when a button is clicked on the login screen
-> I have tried to declare the navigation controller when I click the button of the login screen but that seems to not work
-> Is it safe to say that a navigation controller can only be initialized in the apple delegate?
Currently I have this in my apple delegate declaring and setting my navigational controller:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navigationViewController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; // self.viewController is the main screen
self.window.rootViewController = navigationViewController; // set root to navigationViewController
[self.window makeKeyAndVisible];
return YES;
}
Any ideas will be appreciated. Thank you for your time !
Your code in the app delegate looks ok. NavigationController does not need to be declared in the AppDelegate. In your case, it is definitely ok to declare it upon login button pressed.
Try this at the login event:
UIViewController *nextVC = [[UIViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:nextVC];
[self presentViewController:navController animated:YES completion:^{
}];
What I would do would be set the loginViewController as the rootViewController of the navigation. And after check if login was done successfully, you could implement [self performSegueWithIdentifier:#"identifier"] setting the game viewController as destination. (Using Storyboard would make your life much easier). Well, that's my opinion :)

Resources