I have a CoreData app with the MainView the UITableViewController which houses all of the items in the list. What i'm trying to accomplish is adding a custom back button and using the popToViewController:animated: to access the settings. When I try to use this method the app crashes. After doing extensive reading I realized that push and pop use an NSArray stack for view controllers. For example, the rootView is view 0, when you use pushToViewController:animated: it added in another view, 1 and so forth. That all made sense. What I learned was you can't pop to a view which is not loaded into the stack after the root view. My objective here is to pop to the settings view. When I change the code around in the AppDelegate.m to make the SettingsViewController the rootViewController, the UITableViewController no longer functions, it fails telling me the entity "enityName" can't be initialized. Is there any way to still have the CoreData part of the app function correctly and still pop to the settings? I have thought of using a modal view but it ruins the style of the app.
This was quite hard for me to explain, if you didn't understand any part of it, let me know.
Thanks for your help.
Update: I read in the UINavigationBar documentation that you can use - (void)setItems:(NSArray *)items animated:(BOOL)animated thus allowing you to manually set the array of pushing and popping view controllers. I just can't figure out how to do that. I've gone through apples drillDown sample code, but it didn't have the functionality I was looking for.
Perhaps you are misunderstanding Apple's navigation controller idiom. It is meant for drilling down a hierarchical structure of views and move back and forward easily and intuitively.
A view that is outside this hierarchy (it seems your Settings View belongs to this category) should really be presented modally. On the iPad, you can even use the pretty and convenient UIPopOverControllers.
Of course, if you want to keep your own look and feel (incurring the danger of confusing your users), you could fiddle with the transition animation. You could use Apple's own and thus pre-approved UIModalTransitionStyle property of UIViewControllers.
Or you could try what you did up to now and fiddle with the view hierarchy. Maybe you can eliminate your errors simply by using the view controllers sequentially and not jumping around skipping controllers in between. In this case it should be enough to use
[self.navigationController pushViewController:controller animated:YES];
and
[self.navigationController popViewControllerAnimated:YES];
rather than the more error prone versions pushToViewController and popToViewController.
Related
I have been searching all over the web but I can't seem to find the answer to this.
Currently i am using presentViewController to start new ViewControllers, but on certain view controllers i do not dismiss it and call over it. I currently am not using any navigation controllers or anything like that.
I am just worried that if I call the same viewController again via presentViewController, that the same viewController would have 2 running instances.
Is it possible? Or does the iOS framework automatically reuse the idle viewController?
If so, how do i remove the idle view controllers?
Thank you! (I was holding back my question and tried to find it all over the web, so if you can point me in the right direction, it would be very helpful thanks!)
iOS will not reuse your view controller, you can easily check it yourself by printing your view controller in viewDidLoad, you will notice first that viewDidLoad is called every time, and next that all objects have different addresses.
Unless you create thousand of them, or the navigation of your app doesn’t let you come back to an “idle” view controller, I would not say this is an issue though.
I don’t see any clean way to remove a view controller from the memory without calling “dismiss”. You could try to:
- “refresh” your view with new data.
- use something like UIPageViewController if the workflow of your app allows this kind of behaviour.
- rework the navigation so you can dismiss the view before calling another one
Good luck
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.
so I am building a simple chat app. I will have a login screen, register and later on a UITableViewController so show the friend list. I'm not sure if I should use a UINavigationController for this or just stick to UIViewControllers. Below are two images for the potential setups.:
and:
I'm just wondering is it generally better practice to use a navigation controller? I am also a little confused about what happens to a view controller when it is popped. Does [self.navigationController popViewControllerAnimated:YES]; keep the view controller in the memory to be accessed again later or is a new one created each time? The same question for [self dismissViewControllerAnimated:YES completion:nil], is this destroying the controller or storing it for use later? Thanks
I'll give you my opinion about when to use a navigation controller.
If your app need to present its content in a hierarchical fashion (Master/detail) is pretty common to use a UINavigationController.
If you need to present some content that is not strictly related with the presenting content you can present it using a new view controller on top of it.
Regarding the memory, as soon as you don't keep any reference to the controllers either presented or pushed once remove (popped / dismissed) you loose any reference to them so no space used in memory
I think you will stick to the UINavigationViewController. Simply because the login and registration are belonged to your user management. From the UX standpoints, it's better to use Modal if the scene you are going to present is somehow irrelevant to the current scene. Therefore, go with UINavigationViewController for your situation.
The second question is related to memory management. It's kind of like the reference counting. If you have something to reference the UIViewController, its reference counting won't drop to zero which mean the system won't clean this up. So, you still have way to get then. If you just simply pop then up or dismiss it without referencing it. The reference counting will become zero and the system will clean it.
Note: If you want to simply display a view controller which doesn't need hierarchical navigation or a navigation bar then you wouldn't need to use a UINavigationController.
But in this case I would still suggest to use UINavigationController for the simple fact that your use case (Login Flow) can be completely addressed using a navigation flow.
In terms of memory there is now difference. Feel free to use any of them in this concern. Although how these views are presented has difference.
I'm trying to make a custom tab bar controller by creating a view controller, then add buttons at the bottom of the screen. In this VC, I'll have reference to 4 other view controllers and switching them around when user click on the buttons. I'm not sure if this approach is causing any problem compare to using UITabBarController.
I need to do it this way because the middle tab button will have a 3D object in it, and I think I can't do this with default UITabBarController.
What I'm thinking is that this approach would lead to out of memory issue because I keep too many objects (4 view controllers) alive in memory, and each view controller has lots of image & animation in it. Not sure if this is the same as UITabBarController or Apple has some good way to deal with memory management here.
Please help!
Thanks.
In general I think you are over-optimizing too early if this isn't even a visible problem yet. If you implement your container properly using UIViewController Containment (A good guide here), you shouldn't have any memory issues.
Examples from that writeup:
When you are adding a child view controller (switching to a "tab"), you would do something like:
UIViewController *newTabViewController = [UIViewController new];
[self addChildViewController:newTabViewController];
[self.view addSubview:newTabViewController.view];
[newTabViewController didMoveToParentViewController:self];
Then when you are transitioning FROM a tab, along with the above code to go to a new tab, you would do:
[oldTabViewController willMoveToParentViewController:nil];
[oldTabViewController.view removeFromSuperview];
[oldTabViewController removeFromParentViewController];
Using the containment APIs will call all of the appropriate view lifecycle methods on the viewcontrollers being transitioned (viewWillAppear: viewDidAppear: viewWillDisappear: viewDidDisappear:)
In order to make your individual tabs more memory efficient, just make sure to do any appropriate clean-up in viewDidDisappear: which you can then rebuild in viewDidAppear:.
That said, this is unlikely to be an issue unless perhaps your individual viewcontrollers are keeping very large images in memory or something like that. You have to keep in mind that all existing containers also keep all of their viewcontrollers in memory without issue.
I have a fairly big app made with all view-controllers connected by storyboard segues, before I realized that navigation buttons is a requirement.
I am at a point where I can no longer delete all scenes and start over, nor I can extend the segue approach because its quite overused.
I am looking up for small, elegant solution that will allow all my view controllers to have backward navigation. See my scene hierarchy:
Page 1---> Page 2
Page 1---> Page 3 ---> Page 4
Page 3---> Page 5 and so on.
So I should be able to go back from Page 5 to Page 1 backwards.
I have about 12 screens as of now.
What should I do?
Can I safely mess up with storyboard?
Or should I add code snippets to my viewDidLoads and so on to handle the stuff?
My problem is that when I searched the solution, I found too many approaches including navigation controllers, uinavigationbar, UIBarButtonItem and so on. With each of them, I find it maybe too much for my need, and I need a smaller thing that may just work.
All I may need is only back buttons as of now, but with minimal effort - as I am quite tight on deadline :-(
Appreciate quick help.
I found the answer from apple docs - basically I needed an approach to handle things (instead of straight code), and here it is:
Initialize navcontroller in appdelegate didFinishLaunchingWithOptions method, with root view controller set to first view controller of the app
set appdelegate window's rootviewcontroller = navcontroller
with every 'forward' navigation - use pushViewController along with target view controller
there is no need to handle backward navigation - navcontroller takes care of it by default.
Above will also add extra navigation bar on top of every view controller (except the root view controller of the app's delegate).