I intend to build a rather complicated app and I am wondering how to design it correctly.
I have a rootcontroller that is in charge of dispatching the creation of several Controllers (VC1 to VC5), each of them associated with its own storyboard.
So each of these storyboards are quite complex with several levels of controllers usually driven by a navigationcontroller.
My question is the following : let assume that the user is using the deepest controller in the storyboard of VC1. In this controller there is a button. When the user click it I want VC1 and all the controllers linked to it to close and also to have some data sent to the rootcontroller.
My idea is alse to be able to reuse VC1 to VC5 somewhere else in the app but from a different controller than rootcontroller.
What is the best design to achieve that ?
Thks
First off, there is no best design.There might be better design in this world for everything.
Your First Quest:
You can use Tabbar Controller with 5 Tabs.
Each tab will have navigation controllers for holding your complex design.
For data passing:
Unwind Segue.
Delegates.
Notifications.
For your quest :
user click it I want VC1 and all the controllers linked to it to close and also to have some data sent to the rootController.
There are many tutorials of how to go back to root view controller along with data.One of them is passing-data-between-view-controllers
I don't want to elaborate this whole procedure but the theme is.
One of many solutions:
Assign that data to destination VC' variable before moving to that VC .For navigation controller, to move to rootView controller,
[self.navigationController popToRootViewControllerAnimated:YES];
is used. Hope i've given some light. :)
Related
I have been looking for a solution to this for quite some time but I still fail to see what the best solution is:
I am trying to swap view controllers programmatically, without anything in the storyboard, pure swift files.
As far as I see presentViewController() just creates a 'modal' which would cause the previous ViewController to stay in the memory (tested this, deinit never fires for the first controller). The solution I have found is to switch the rootViewController: self.view.window?.rootViewController = ViewController2() -> this fires deinit of the first one.
While this solution would work in theory, I am wondering...
Is there some recommended way or best practice of how to do this programmatically? Or is it really just about changing the viewRootController's value?
How do you structure your app? Do you use one ViewController and you swap views? Or you present other ViewControllers as modals with presentViewController? (I am totally new to this and I can't seem to find any good source; most of the articles deal with storyboard)
Thanks a lot!
EDIT: I will add: my test app is not supposed to have any kind of navigation for different viewcontrollers (no tabs, nor anything like that). It basically works like screen1->screen2->screen3->screen4. If a reset button is pressed, it gets back to screen1. I am purely interested of swapping ViewControllers, nothing else.
1: Changing the main window's root view controller is correct for swapping view controllers.
2: Generally, swapping view controller is not used. You can use a navigation controller that has a root view controller (eg. your main screen) and then push other view controllers as needed. Tab bar view controllers are also very useful.
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html#//apple_ref/doc/uid/TP40011313-CH6-SW1
Hope this helps!
1.
The basic ways are:
navigationController?.popViewControllerAnimated(true)
or just pop to root view
navigationController?.popToRootViewControllerAnimated(true)
pushing can be done similarly
or setting a new stack
navigationController?.setViewControllers([viewController], animated: true)
These are the recommended ways of navigating in code just pick the one appropriate to your specific situation.
The push and pop mechanism is probably the most recommended way of doing general navigation.
Try to always use navigation controllers and only use modal views when appropriate.
Use navigation controllers when navigating through your main views. Modal views can be used as side views or extension to the view presenting that view modally.
Edit:
There are many ways of efficiency navigating through an app. In this particular case pushing and popping the navigation stack is probably the best way to go. But keep in mind that there are Tab bar controllers, collection views and others. At the end of the day The best is to look at your app structure and based on that decide which navigation method is the best for you.
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!
The app I'm working on will need to implement a workflow to allow users to enter information in a form. Instead of using a scroll view, I'm planning to break it up into a bunch of separate view controllers, which will be managed by a navigation controller. I started by laying out all the form fragments in a storyboard, and began connecting all the push and unwind segues for the different parts of the form.
My question is, how is using all these push and unwind segues any better than simply using the pushViewController and popToViewController methods of my navigation controller, and skipping the storyboard altogether? Is there any difference in terms of memory management or performance? Wouldn't simply using push and pop be better practice in terms of design and maintainability? I can't find anything in the docs that addresses this.
There's basically no difference in terms of what they do. The one thing that's good about using unwinds, is that you can pass data back to the controller you're unwinding to. If you use the pop methods, then you have to create a delegate protocol to do this. But a lot of this is subjective. You can use which ever is more comfortable for you. I like using the storyboard because it makes it easy to see the relationships between the controllers. Using storyboards can be a problem (so I've heard anyway) when you are working in a large team, so that's another consideration.
This is a great question.
In my 1st iOS project I followed the tutorials online and used storyboard segues etc. In my 2nd iOS project, I scrapped that and just push and pop view controllers.
I actually find it cleaner because with the storyboard way, you have to call performSegueWithIdentifier, and then you can prep the receiving view controller by sync'ing up with prepareForSegue. Why do this when you can just prep a view controller and push it all in one place?
Additionally, it decouples view controllers with transitions. It opens everything up and allows for more versatility..and more rapid development.
So my take on the matter is to just push and pop view controllers. Maybe somebody will make me look dumb but I've had much success just using this method.
For this case
(NAV_A --root view controller -- VC1) -- modally presents -- (NAV_B -- root view controller -- VC2 -- push -- VC3)
If you do pop at VC3 you will always reach VC2, ie view controller just below it.
With unwind you can do what you did above plus , jump back to VC1 in one go.
Unwind can take you back to any point in the view controller hierarchy that you want but not pop.
I have read here a lots of questions and answers regarding segues and story board , and i became even more confused about the way i build the hierarchy between views
My questions are very basic and simple, and i think they may be helpful to others :
1.In a simple words, when should i use push , modal, or costume segues ?
2.When go from view1 to view2 to view3,how should i go back from 3 to 1? can i just drag a segue from 3 back to 1? and what happens with 2 and 3 with memory aspects in that case ?
3 when dismissing a view, why it always go back to the previous view? is there a way to make a segue that dismiss automatically the previous view ?
I think a very simple and short summing on the way it works would be so helpful.
thanks.
If you are using Storyboards and segues you may want to take advantage of exit segues for going back. In your example you want to go from View 3 back to View 1. Depending on how you got there, you may have multiple options to go back. For example, if you used a UINavigationController and pushed your way there, if View 1 is the rootViewController you could simply call popToRootViewControllerAnimated: and it would handle what is necessary to get from wherever you're at in the navigation stack back to the root. If View 1 is not the root you could opt to use the popToViewController:animated: API instead, assuming you have a reference to View 1 from View 3 which usually isn't ideal if you're keeping concerns separated. As Renish pointed out you do have the option of accessing the viewControllers property of your navigationController.
Back to Storyboards, for better or worse, they can handle this all for you via an exit segue. The storyboard configuration determines the proper way to go back to a view that you came from. Check out this great explanation in this answer, https://stackoverflow.com/a/15839298/250190
I think u want How to Go 3view to 1view.Simply make array of Your view controller.
How do I get the RootViewController from a pushed controller?
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/Reference/Reference.html#//apple_ref/occ/instp/UINavigationController/viewControllers
Use the viewControllers property of the UINavigationController. Example code:
// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];
This is the standard way of getting the "back" view controller. The reason objectAtIndex:0 works is because the view controller you're trying to access is also the root one, if you were deeper in the navigation, the back view would not be the same as the root view.
What is the difference beetween calling presentModalViewController and pushViewController, when :
animation is set to NO (even if yes, that's just an animation style that can be changed).
a navigation controller is defined when presenting the modal view, so it can be navigable too, with a call stack, ....
Is this just to be able to go back from the first pushed view ? Woooaaaaaa.....
I guess the difference is elsewhere and deeper. No ?
Ignoring transitions/animations and how things are structured behind the scenes (which aleph_null's alswer provides a good discussion of), the only user-facing difference is the ability to return to the preceding view automatically using the navigation bar.
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.
The most important difference is about semantics. Modal view controllers typically indicate that the user has to provide some information or do something. This link explains it more in depth: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html
Here's another, less abstract difference they talk about:
"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."
Also see this thread: why "present modal view controller"?
Take a look into the viewControllers in the image
The top 2 viewControllers(login & submit) at the top left are disconnected from the tabBarController & NavigationController
The rest of the viewControllers are embedded in a NavigationController. They somehow belong to the natural flow of the app.
Now you have to ask yourself
Do I need to always show login + submit page every time? It would be pain in the neck for the user to each time go to login even if they logged in last time. These 2 screen really don't fit the natural flow of the screens. So what do we do? We just add them modally using presentViewController
However for the rest of the viewControllers we want to keep them inside 2 navigation so we can easily go back and forth so we use pushViewController
For more information I recommend you to see this video
The image was also picked from this great answer. It's worthy of a look.
This is what my experience says,if you want to manage a hierarchy of views,better go for pushViewController in the navigation controller. It works like a stack of view-controllers in the navigation controller. If however the requirement is just to show a view on executing some actions on the parent view controller then the best way is presenting it modally.
If you need a complex push pop logic always prefer a pushViewController.
UINavigationController are used when you want to have some sort of hierarchal representation of your data (ie drill down). They work using a stack of UIViewController subclasses. Every time you “drill down”, you simply add another view controller to the stack. Then, the “back” logic is simply a matter of popping view controllers off of a stack.
You can check out this link:
http://www.icodeblog.com/2011/10/11/back-to-basics-an-introduction-to-view-controllers/