Moving to any of several view controllers from any of the others - ios

The app I am developing has five view controllers.
Lets call them A, B, C, D, and E, with A as root view controller.
A will have four buttons to navigate to each of the other view controllers. Similarly, B, C, D, and E will have four buttons each to navigate to all other view controllers.
Is it a good idea to to use presentViewController: to implement the navigation, since there is no clear hierarchy in the relationship of the view controllers? I don't think I clearly understand the presented vs presenter relationship.
Does the dismissal of the presented view controller have to be handled by the presenter?
Suppose A presents B, and B then presents C, and C then presents A. Are any of the controllers released/dismissed? Who is handling whose dismissal? When A is finally presented, is B still in the memory?
The other approach I thought of is to design and write a View Controller Container and manage all the view controllers. I have read this is not an easy territory to walk on.
Which of these makes more sense?

You can use UINavigationController to push new controllers to the stack. If you don't want user to go back (it means not keeping the old view controllers in the stack) you can simply set the newly allocated view controller as the root vc:
-(void)buttonAPressed:(UIButton *)button {
AViewController *vc = [[AViewController alloc] init];
self.view.window.rootViewController = vc;
}

if your situation is that you have 5 instances of view controllers and you use just the same, you have to use the container solution. If you use the same instance, you have in each time allocated just this 5 and so you haven't problem.
If instead, you need to navigate in depth with new instance, and after came back (like a navigation controller) the best solution is instantiate each time a new view controller and when you came back to the previous, the last is dismissed.
N.B. If you need to open many instance in depth but potentially without come back (like a navigation controller) you need to use the first solution, because you have to use 1 instance for each view controller.

Related

ViewWillAppear & ViewDidAppear firing when dismissing ViewController

I am making an iOS app where I want to present a flow of pages like this:
Basically I want to achieve is to have this flow of pages:
PageA
PageB
PageC
PageD, dismiss back to:
PageC
PageD
PageE, dismiss back to:
PageA (starting point, start over again)
I am using ShowViewcontroller to present the pages (modal) and DismissViewcontroller to dismiss.
As per Apple's documentation if I dismiss a VC early in the stack all subsequent UIViewCOntroller are dismissed too (Apple doc).
However I experience that ViewWillAppear and ViewDidAppear are fired on the UIViewController that are dismissed even when they do not appear (e.g. in the example when dismissing back to PageA from PageE then ViewWillAppear is called on PageD, PageC, PageB too).
This does not seem logical to me. Can anyone explain why this is happening? And perhaps correct me if I am approaching this the wrong way.
I am using Xamarin.iOS.
Apple doc:
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
The ViewControllers work with a stack. Whenever a new ViewController (of any type) is added to the stack, You lose more and more control of your ViewControllers (especially when using a modal for your ViewControllers). So, say you have 5 ViewControllers in your stack (A, B, C, D, E, as per your example), and assume they are created in the order as stated, in order to return from ViewController E to ViewController A, you'd have to go through the entire stack. That means that every ViewController in your way needs to be displayed first, in order to dismiss is (since you already have ViewController E displayed, this doesn't occur here).
I hope this helps you. Good luck!
Love and regards,
Björn

iOS App navigation

My Application flow is as below where A, B , c and D are view controllers.
Arrows mark presenting from and to view controllers.
Now I need home button in B , C and D view controller that navigate back to A.
I am not using storyboard.
Its I am unable to use dismissviewcontroller as it dismisses just once, where in some cases its required 2 or 3 previous view controllers dismiss.
Any suggestions in this regards will be helpful.
It sounds like you should be using A as your root view controller on a UINavigationController. The only thing B, C, and D will need to do is call popToRootViewController.
You'll need to make your login view controller be pushed from A, but you can do it without the user seeing it by putting the code in the AppDelegate (which is likely where you're checking to see if the user needs to log in anyway).
How about using setViewControllers:animated:. Where ever you are, you get the first View controller as firstViewController = [self.navigationController viewController] firstObject], then [self.navigationController setViewControllers:#[firstViewController] animated:YES].
See here: setViewControllers:animated:

Does presentViewController clean up the parent view?

Here is my issue.
The App I am creating has non-linear navigation.
So I am implementing my own back button and doing my own navigation.
However, I am wondering how I should be presenting the next view.
If my navigation was linear, I could do:
-(IBAction)btnBackPressed:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
However that will not work for me since pressing back may not necessarily bring you back to the previous view.
Therefore I am thinking of using for example:
AddTaskViewController *add = [[AddTaskViewController alloc] init];
[self presentViewController:add animated:YES completion:nil];
The reason I am not using Storyboard is because all my UI is made programmatically in code.
The worry I have with this is that I think presentViewController will just push the new view on top of a stack. Thus, if the user presses back, forth, back forth, he will eventually run out of memory.
Given my circumstance that I need non-linear navigation and all my UI is created in code, what should I use to present the next view without wasting memory?
Thanks
If you are still interested in a clean solution using UINavigationController, consider this design.
Situation: Let A and B be types of view controllers. A is the root, and B is a detail view which can push or pop to other B controllers.
Goal: We want to delete any B controllers that are not adjacent to the currently presented view controller, but maintain the hierarchy so we can recreate the views when necessary. Thus, the maximum hierarchy the navigation controller will know about is A--B--B.
Design: Make A the navigation controller's delegate. Give it an array of model objects which represent B controllers enough to recreate the views from them. Add to this array whenever a B controller is pushed, which A will know about from the navigation controller delegate methods. Remove objects from the stack when a B controller is popped.
On pushing a B controller, the A controller will take the navigation controller's view controller stack and (if it exists) remove the B controller directly before the one that was displayed before the push. On popping a B controller, the A controller will (if it exists) recreate the B controller directly before the destination controller and insert it in the stack.
Example: Let's say A has kept track of a hierarchy like this: A--B1--B2--B3--B4. By the system outlined above, the navigation controller only knows about A--B3--B4. When the user pops B4, the A controller will be notified and recreate B2, inserting it before B3. Thus, the new hierarchy is A--B2--B3. When B5 is pushed from B3, B2 is removed to produce A--B3--B5.
I realize this is a fairly complicated system to implement, so I would only recommend it if you had a large number of controllers and required the amenities of UINavigationController. Another solution that occurs to me is UIPageViewController, which allows you to provide view controllers on the fly.
Hope this helps!
Yes you are correct that the user will eventually run out of memory if you keep presenting Modal view controllers using
[self presentViewController:add animated:YES completion:nil];
and
[self dismissViewControllerAnimated:YES completion:nil];
will only dismiss the top most viewController being displayed.
Instead you would be better off building your own container view controller and handle your own navigation. For more information read the "Implementing a Container View Controller" section in the UIViewController Apple documentation.
https://developer.apple.com/library/ios/Documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html

Manipulating view hierarchy by code

If I have a UITabBarController (2 tabs) as root view controller then in the first tab (FirstTabViewController) I init a UINavigationController with a root view controller AddReminderViewController and present it.
Then inside AddReminderViewController I present another UINavigationController with a root view controller called ChooseOptionViewController and present it.
Now when I'm inside ChooseOptionViewController I want to programtically go back to FirstTabViewController how can I do this as easy as possible? Do I need to - dismissViewController... on all view controllers that I have presented or is there an easier way?
Also inside ChooseOptionViewController how can I find out the class that presented ChooseOptionViewController? I tried doing [self.presentingViewController class] but that just says UINavigationController (not AddReminderViewController)
Now when I'm inside ChooseOptionViewController I want to
programtically go back to FirstTabViewController how can I do this as
easy as possible?
You really ought not to have the ChooseOptionViewController try to manage all that by itself. It should simply tell its parent that its job is done and let the parent dismiss it. The parent could then tell its parent that its job is done, and so on. This approach will make it much easier to maintain your code, and to change things around when you decide that's necessary, without breaking ChooseOptionViewController.
For example, imagine that AddReminderViewController wants something else to happen, like presenting ChooseMoreOptionsViewController after ChooseOptionsViewController has been presented. If AddReminderViewController is in charge of the flow of its part of the program, that's easy. If ChooseOptionsViewController knows enough about the reset of the app to dismiss view controllers all the way back to FirstTabViewController, you'll have to modify it every time there's a change in the flow. That's not a recipe for long term success, and it adds a lot of unnecessary and unhelpful complexity.
generally unless an exception you should use only one navigation controller.
keep pushing view controllers onto it.
in that way you can move pop top to root view controller.
for ex:
1
just add one navigation controller to tab 1
2
setrootviewcontroller of navigation controller to FirstTabViewController
3
from FirstTabViewController you can push AddReminderViewController(using the same navigation controller)
ex:- [self.navigationController PushViewController:....];
4
from AddReminderViewController you can push ChooseOptionViewController(using the same navigation controller)
ex:- [self.navigationController PushViewController:....];
5 finally use [self.navigationController popToRootViewController];

IOS Navigation Non Heiarchical

I have an iOS app using iOS 5 and Xcode 4.3.2 that is made up of 7 view controllers. VC1 links to VC2, VC2 can link to VC3-VC7 and each of those controllers can link to each other (think of it as a side bar navigation). If I use segues the views are repeatedly added to the stack and if a user goes back and forth it can use a large amount of memory. How can I implement this navigation where I release the previous controller? They are all small controllers so loading them takes little time/processor/memory. Can I presentViewController and then release the presentingViewController somehow? Thanks.
If you implement a UINavigationController, you can use the push and pop view controller methods to go back and forth. popToViewController:animated: is described here, along with 3 other helpful methods.
Well seems like there should be no problem from VC1 to VC2. For the VC3 - VC7 you could:
Present as modalViewController instead of pushing that to the stack.
Or:
- Use the popToViewController:animated: function of your UINavigationController if the Controller is already present in the stack of controllers, otherwise push it. Like
// Assuming u need to push VC6
for(UIViewController *controller in [urNavController viewControllers]){
if([controller isKindOfClass:[VC6 class]])
{
[urNavController popToViewController:controller animated:YES];
}
else{
VC6 *VC6controller = [[VC6 alloc] init];
[urNavController pushViewController:VC6controller];
}
}
You could use UINavigationController's - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated method to remove any view controllers below the topmost one. Since the navigation controller's viewControllers array is an immutable one, you could not use any NSMutableArray's removeObject... methods directly on the viewControllers array. You would have to make a mutableCopy into a mutable array, remove any (hidden) view controllers you wish to discard from the mutable array, and pass the resulting slimmed-down stack of view controllers to the above method. Since your topmost view controller would be unchanged, there would be no transition animation in your case (see discussion below), so you could also set the viewControllers property directly without bothering with the animated: argument.
From Apple's documentation:
Discussion
You can use this method to update or replace the current view controller stack without pushing or popping each controller explicitly. In addition, this method lets you update the set of controllers without animating the changes, which might be appropriate at launch time when you want to return the navigation controller to a previous state.
If animations are enabled, this method decides which type of transition to perform based on whether the last item in the items array is already in the navigation stack. If the view controller is currently in the stack, but is not the topmost item, this method uses a pop transition; if it is the topmost item, no transition is performed. If the view controller is not on the stack, this method uses a push transition. Only one transition is performed, but when that transition finishes, the entire contents of the stack are replaced with the new view controllers. For example, if controllers A, B, and C are on the stack and you set controllers D, A, and B, this method uses a pop transition and the resulting stack contains the controllers D, A, and B.

Resources