Alright I'm really failing to see what the big win in having Navigation Controllers wrap my views and trying to drag segues on my Storyboards are. Sure you get the benefit of iOS automatically adding a back button as you push/pop views off the stack, but for anything past a simple app, I don't even care for that!
My goal is simply to have 1 view actually represent a given page. Then just programatically move to another view using:
ViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:modalYearPickerViewController animated:NO completion:nil];
or
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:vc animated:YES];
I realize that in order to push with the second example I'd need the view to be wrapped in a Navigation View Controller, however using one of these methods prevents my from ever having to create "segues" which I find hard to manage. Half the time when I setup a segue iOS throws an error saying it cannot perform or the segue doesn't exist.
A lot of the time I'm either hiding back buttons or on the fly changing where "back/return" may drive the user based on previous actions or screens.
Anything massive I'm missing here? I am fairly new to iOS but I come from the web world where I'm used to being able to navigate around screens with ease.
Anyone have any thoughts?
EDIT: Here is a dead simple example solution. When I get to the "details" page I want to have a back button to the home page instead of the modal.
http://andrewherrick.com/spike/nav_ios.zip
From your diagram, I'd expect:
At the root, you have a navigation controller which contains the Artists. Artists has a modal segue to New Artist (well, to a nav controller containing it) and a push segue to Artist Songs.
New Artist is the root of a navigation controller and has a push segue to Artist Songs. New Artist has a Cancel and a Done button in the navigation bar.
Artist Songs should be configurable (it could determine this itself), such that it has a back button (always based on this model, and automatically handled) and a Done button when it is pushed from New Artist (which completes the save and dismisses the modal, thus taking the user back to Artists).
All of the above is a achievable either with segues or direct instantiation and transition from code, which you use is a matter of personal preference.
Related
I have two method to jump from one viewcontroller to another
For presentViewController
[self presentModalViewController:view animated:YES];
For pushViewControlle should use
[self.navigationController pushViewController:view animated:YES];
Which Will be best approach ?
Which will cause more memory leak?
Which one is use if Our Design is like
Introduction view (bunch of slides )-> login -> signUp-> HomeActivityScreen-> Then Bunch of tab bar in it
If you use pushViewController you will automatically get a "Back" button in the navigation bar. If you use presentModalViewController you do not, and generally will have to implement your own controls and/or callbacks to handle dismissing the controller.
Conceptually the modal presentation style is generally used for atomic tasks that you cannot navigate away from (i.e. you either complete the task, or you cancel, and you cannot do anything else within the app until you do one or the other).
If you're wondering why have the difference in the first place, I can't say. Personally I think frameworks that provide a unified API for moving from one controller to another (like cocos2d, or Android) make a lot more sense.
You use modal view controllers to focus the user's attention on a Task. When you push, the user is in some kind of navigation flow, but still has the total application at their fingertips. They might decide to go forward or backward, switch to a different tab in the middle, whatever. When they get a modal view controller, they can't do any of that until the task is completed or canceled out of (the modal view is dismissed)
When you present a modal view controller, the system creates a parent-child relationship between the view controller that did the presenting and the view controller that was presented. Specifically, the view controller that did the presenting updates its modalViewController property to point to its presented (child) view controller. Similarly, the presented view controller updates its parentViewController property to point back to the view controller that presented it.
Modal view controllers provide interesting ways to manage the flow of your application. Most commonly, applications use modal view controllers as a temporary interruption in order to obtain key information from the user. However, you can also use modally presented view controllers to implement alternate interfaces for your application at specific times.
So, from my understanding this one is best option.
[self.navigationController pushViewController:view animated:YES];
Apple handles the memory for both of these through Automatic Reference Counting. Although pushing a view controller might require more memory than presenting the same, the allocated memory is released when popping or dismissing the ViewController. ARC releases the said memory if no strong references are made from within the popped ViewController, or in other terms, the ReferenceCount is 0. So care must be taken so that no strong references are retained to the ViewContoller's objects.
Now whether to present or push a ViewController depends solely on your app design. Read this to get an outline on when to present a ViewController, .
They are two approaches to navigate from one view controller to other view controller.
By default:
- pushviewcontroller: you will have a back button to return to last visited page. your viewcontroller is put on top of the navigation stack. Think like a webpage when you navigate between pages.
- presentmodalviewcontroller: you have nothing to comeback to last visited page. It is usually used for: a pop-up or to change to new branch of navigation.
The use of pushviewcontroller & presentmodalviewcontroller does not produce memory leaks.
For your application flow, I suppose that HomeActivitiesScreen is one of viewcontroller in your "bunch of tab bar". If so, create a viewcontroller that contains that tabbar and make it as root of your application (named RootViewController for example). Then:
When application is launched, you show the RootViewController
And immediately, present the modal view to your "introduction pages", then login/signup. This modal view start with a Navigation view controller structure.
When the user is connected, dismiss your modal view, return back to your HomeActivitiesScreen and refresh contain if need.
Like this, you do not keep the reference to your login/signup screen when you do not need.
I am developing an application with iOS 9 based SDK , this is my first time I am working with Storyboards , I have 20 view controllers, each scene has Next / Previous buttons to go back and forward . I have a huge problem with going forward !. If I move from scene 1 to for example to scene 15 I received memory warning and then application crashes . I have searched and it seems there is method called unwind segue but it seems this is for going back ! it's something like dissMiss method .
I connect each scene with line in Interface Builder :
Here is segue's setting :
I would be grateful if you help me out .
EDITED :
I tried to present a view controller programmatically but result was the same ! .
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
WhatIsDino *vc = (WhatIsDino*)[mainStoryboard instantiateViewControllerWithIdentifier:#"WID"];
[self presentViewController:vc animated:YES completion:nil];
Seems like it's a problem of wrong approach, and not the storyboard.
Let me guess, since before storyboard you used to change your app's rootViewController to the next/previous screen once you tap on the arrow button. So previous screen are released and deallocated from memory once you set a new rootViewController.
And now you're presenting every next view controller modally, which involved creating new UIWindow and loads all the hierarchy of you screen and keeps previous underneath the new one so it holds the memory and you're getting out of memory crash.
Well, you can do rootViewController approach with a storyboard too since it's just another way to manage your screens while development. Storyboard offers additional features like segues, static table view cells, general tint color and so on. [UIStoryboard -instantiateViewControllerWithIdentifier:] is the method you might find interesting.
But I'd rather recommend you to check out the UIPageViewController, it's like a container for the screens. Unfortunately, it cannot have the segues to your scenes (because of the special way segues work) so you have to use -instantiateViewControllerWithIdentifier: method anyway. You can treat inner view controllers of UIPageViewController as you do with rootViewController before.
You can also navigate without segue and Its easy way I think.
If you want to navigate from Class1 to Class 2 then follow these steps.
1) In Class 1, Import Class2.
2) In your button Action, Write this code.
Class2 *next = [self.storyboard instantiateViewControllerWithIdentifier:#"Class2 Identifier name"];
[self.navigationController pushViewController:next animated:YES];
Do not forget to give Identifier name in story board that is "Storyboard ID" in Attribute inspector of particular class.
No need to add Segue,Your storyboard would look clean.
The problem is that you are adding view controller after view controller with modal presentation. That causes each view controller to be added on top of the previous one, and all of them accumulate, using more and more memory.
Using a navigation controller and a push also piles the view controllers on top of each other.
You will have this problem if you use storyboards, nibs, or create the view controllers manually.
If you have a design where the user can move through a large series of view controllers then you probably want to dismiss the previous one before pushing/presenting a new one.
You can probably dismiss the previous view controller without animation and then present the new view controller each time you want to display a new one and avoid the memory issue. i'd have to experiment with it to get the effect I was after, but that's what I would suggest.
I've got a single navigation controller that houses the primary view of the app (A dashboard of sorts) which then branches off to the other views in the app via segues etc..
There's a hamburger menu, which makes use of a Cocoa Pods sliding view controller. Basically, my question is is it possible to navigate to specific view controllers via the menu and maintain the correct "stack" going back. I'm aware you can just push to a single controller, but I'd like (if possible) to retain the view hierachy going back.
E.g.
There's a link in the menu to Page 1.3
I want to be able to push to Page 1.3
Then have the back button on that view to go to Page 1.2, then Page 1.1 etc..
I'm not sure whether this is standard practice in iOS apps, or whether it's better to adopt an Android esque approach and just add views to the stack, not worrying about trying to form the correct navigation structure when they go back through the views.
Hopefully all of that makes sense.
If you are happy to do it in code, rather than a segue, you can use the UINavigationController's setViewControllers:animated: method (see the documentation). You will need to instantiate the relevant VCs, initialise them with any relevant data/state, and then build an array with them in order from the root view controller to the top view controller:
NSArray *newStack = #[rootVC, ..., page11VC, page12VC, page13VC];
[self.navigationController setViewControllers:newStack animated:YES];
Then popping from page13VC will go to page12VC, etc, etc. You can get rootVC and any other pre-existing VCs using the viewControllers property of the navigation controller.
I meet the same problem in my project,here is my experience.
If you just want to do simple jump, you can try the three basic navigation function:
[self.navigationController popToRootViewControllerAnimated:YES]
[self.navigationController popToViewController:[[self.navigationController.viewControllers count] - mypopcount] animated:YES];
[self.navigationController popViewControllerAnimated:YES];
Bind the action with the button, you can do that.
But, if you want to do more flexible page jump in ios, you must consider:
First of all, you need to confirm that there is no direct data interact between these view controllers, which means you need coreData or other sqlite tools to store data, so the destination page can load data itself.
Secondly, you should consider the strategy, page jump means pop all viewcontroller and push a new one, or just pop or push a new one just on the navigation stack.
Good Luck!
I am using a UINavigationController within my app (as expected) for a specific path the user takes when taking a turn in my turn based game.
When they move through the turn controllers they do not actually have the option to go Back from the Navigation Controller. This is planned/expected behaviour.
My question is, is it best to keep the other controllers on the UINavigationController stack when they are not going to be used again.
Should they be de-alloced immediately, or wait for the whole turn to be complete and let them go when the navigation controller goes (how it is at the moment). Some of the controllers hold data/images etc as properties so I am wondering if it would be more efficient to get rid of these on the fly?
If it is, what is the best method to load new controllers into the UINavigationController at present I am using self performSegue... or buttons that push to the VC from the storyboard setup.
You can manipulate navigation controller viewControllers using this code
NSMutableArray *viewControllers = self.navController.viewControllers;
//remove or add in the array
[self.navController setViewControllers:viewControllers];
I have an app that has the following basic layout, please understand I have done a lot of programming, but I am relatively new to IOS and am yet to wrap my head around the Storyboards/segues properly yet.
Effectively, my app has the following screens:
WelcomeViewConroller ---ModalSeque--> MenuViewController --modalSegue---> newProjectVC || loadprojectVC ---modalSegue-->ProjectScreenVC.
From the project the screen, the user can return to the menuVC screen.
Now, I understand that every segue creates a new instance of a view controller, which is great, I want this to happen, however, when I segue back from my ProjectScreen, and then reenter it again, I get a huge memory leak and very strange behaviour.
I understand that I need to dismiss my View controllers, especially my ProjectScreen when I leave it, however, I can not get this to happen, no matter what I try.
Any help would be greatly appreciated.
In How should I chain viewcontrollers in xcode storyboard? I enumerate a series of ways of going back multiple scenes in a storyboard. But in short, the two easiest options are:
Unwind segues: If only supporting iOS 6 or higher, use unwind segues. So, for example, in your main menu's view controller, implement a unwind segue:
- (IBAction)gotoMainMenu:(UIStoryboardSegue *)segue
{
// if you need to do anything when you return to the main menu, do it here
}
Also make sure to define that in the main menu's .h. Then control+drag from the button that you want the segue to the "exit" button in the panel below the scene, and choose the "gotoMainMenu" option:
Navigation controller: If you need iOS 5 support, then just use a navigation controller and replace the modal segues with push segues. Then you can use popToViewController or popToRootViewControllerAnimated to jump back multiple scenes. If you don't want to show the navigation bar, then select the navigation controller in your storyboard, and in the attributes inspector, uncheck "Shows Navigation Bar":
In this scenario, I actually think it's easiest to make sure your menu scene is the root (and have it do a little detour to the welcome screen, like I discuss in point 4 of that other answer), in which case you can just call popToRootViewController whenever you want to return to the main menu. But, if the main menu is not the root view controller, and you want to pop back to it, you can either pass a point menu controller from scene to scene, or you can have subsequently presented view controllers do something like the following when they want to get back to the main menu:
for (UIViewController *controller in [self.navigationController viewControllers])
{
if ([controller isKindOfClass:[MenuViewController class]])
{
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
Elsewhere on Stack Overflow, you'll see people contemplating ways to nest calls to dismissViewControllerAnimated, or other variations like that. I personally think that navigation controllers and unwind segues are far easier and more elegant.