I have an app that uses UIViewControllers for everything pretty much. So far I have been using push segueys when there are either button clicks, or some logic after which I have to show a new screen.
Sometimes it works and sometimes I get strange behavior where the next page loads and gets stuck, and its nav bar area does not load.
I use this code:
BusinessController *businessController = [[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"BusinessController"];
[self presentModalViewController:businessController animated:YES];
I have been reading that I should use the modal seguey possibly, but I am not sure which one is better.
Also, I have been reading that I need to embed my controller in a NavigationConroller if I want to to push, but I am not sure what effects that will have on the rest of my app.
Please help me understand what is the right approach here for me.
Thank you!
For the record....
If you're creating segues you ought to use them, either by linking them to a control so that they activate automatically or by calling performSegueWithIdentifier:sender:. (As a general statement, modal controllers are an interruption of program flow while pushed controllers are like a stack you move though back and forth.)
Related
Body:
I am getting a Memory warning in my app, after which the UI stops responding. And, in the XCode logs I do see ViewController being Unloaded message.
I am afraid it is because I am not handling the transitions between the views properly and which is causing this memory issue.
Brief description of the ViewControllers(VC) I have and how I perform the transition:
I have 1 main/home VC which is the start of the main workflow of my app.
And from all other VCs, I have links to come back to the Home VC.
So, instead of having Segues from all the VCs to the 1st one, I use the following way:
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main_iPad" bundle:nil];
HomeViewController *homeViewController = [sb instantiateViewControllerWithIdentifier:#"HomeView"];
[self presentViewController:homeViewController animated:YES completion:nil];
Intention was to just avoid having so many Segues from all the Views connecting to the Home View.
I feel this way of transition is causing the memory issue. Same View is getting added to the stack several times and causing the issue.
I am no expert of iOS, so any help/suggestion will be of great help to me.
It looks like the way you have it you're creating an entirely new ViewController everytime you intend to transition back to the HomeView. This is a very bad idea because everytime you make a transition you're putting a new view controller on the stack, rather than using the original ViewController (which you should be doing).
So as you keep making a transition, you're allocating new memory which eventually causes a memory warning then causes a stack overflow making your app crash.
HomeViewController should be presenting other view controllers using this method presentViewController:animated:completion: and dismissViewControllerAnimated:completion: or something similar in order to perform transitions if you don't want to use segues.
Please read this apple documentation:
https://developer.apple.com/library/ios/featuredarticles/viewcontrollerpgforiphoneos/ModalViewControllers/ModalViewControllers.html
In my view controller if I navigate through the Root view controller it works okay through this code,
[self.navigationController popToRootViewControllerAnimated:YES];
But when i try to custom navigation to viewcontroller through below code,
ViewController2 *vc = [[[ViewController2 alloc] init]];
[self.navigationController popToViewController:vc animated:YES];
by this my application is crashed and show me the Below error:
terminate called throwing an exception.
Help me to shortout it.
uinavigation just like a box , you can push anyVC in this box , but when you want to out ,you just popToRootVC .. you can't push VC that it outside in this box .
You can only use that method to pop to a vc already in the array of view controllers.
EDIT: as developer new to iOS, you need to spend the time to read (and re-read) the UINavigation Controller class description, and the two or three Apple Guides on using UIViewController and the catalog of various view controller. Yes, its a lot of stuff to read and comprehend - but then, all of us doing iOS work now have done it too. There is no magic way to get your app to work. Your use of popToViewController demonstrates to the community that you have not done the above, as you would not have posted the question if you'd read the documents.
People who try to help others here on SO are much more likely to do so if it appears you have made an honest effort to get something to work, but are stymied in some way where an experienced person can provide insight.
I am just looking for a sanity check here.
I have a screen that the user passes through on the way into the main application. That screen can be navigated back to from almost anywhere in the system.
As it stands I am just presenting ViewControllers without using a NavController to manage them (it does not seem applicable for most of my app, since screens are not necessarily sequential or related to one another).
My question is, if I have presented VC1, then navigate to other screens, and finally want to present VC1 again, I am doing something like:
[self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"VC1"] animated:YES completion:nil];
Is this bad form? Am I leaking memory by creating a bunch of VC1 instances or is there some magic that uses the previously created one?
If it is bad form, how do I get back to the original VC1 to reuse it?
Thanks for any input.
I think you pegged it: It's not a great idea to have multiple instances of the same view controller in memory at the same time. Every time you instantiate a new view controller and present it modally, you'll consume more memory.
The most elegant solution is the iOS 6 unwind segue. But most of us would be unwilling to give up on iOS 5 support quite yet.
If you need to support iOS 5, you could contemplate using navigation controller, but hide the navigation bar if you don't like it in your user interface. Then replace modal segues with push segues and now you can do popToRootViewController whenever you want to return to the main view controller.
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.
Simplified question: Is there any way to restart the navigationController of an application?. I'm trying to force the application to get his initial appearance.
Long explanation
I've a pet project in iOS and I have a weird problem with the interface that I'd like to solve. I'd like to understand also the mechanics behind this behavior.
I've a simple welcome view, wich shows the splash screen of the application. After that, thread goes to sleep state for 1.5 seconds.
[NSThread sleepForTimeInterval: 1.5];
Then, I'm showing an advertisement view:
AdController *ad = [[AdController alloc] initWithNibName:nil bundle:nil];
[self.navigationController presentModalViewController: ad animated:YES];
[ad release];
And that's all the logic behind. After that, other controllers are pushed without incidence. I want to achieve that, if at any moment the user makes the application go to background (pushing the iPhone/iPad button) then all the controllers must disappear from the stack via pop. In order to get it I'm using applicationDidBecomeActive event from the delegate. The code is the following:
[self.navigationController dismissModalViewControllerAnimated:NO];
[self.navigationController popToRootViewControllerAnimated:YES];
This is driving to some weird visual behaviours. Depending of the moment that the user choose to push de button the transition to the first view is visible. In other cases the ad view is still present, so it is dismissed and then appears the splash screen.
It will be great if there is some way to reset this first controller (splash screen), in order to get all the transitions working as the first time. I've thought about pop it from the navigation controller and the reload another one, allocating again, but it seems a bit complicated.
Is there any simple way to achieve that?
Important Edit: If the user forces repeatedly the application to go background then these exceptions are thrown:
nested pop animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
The easiest way that I've found is to add to the plist file a new row with key "Application does not run in background" and with value YES.
Forces the application to be completely closed and unloaded from memory when the user pushes the button.