We are building a data acquisition app that allows the user to enter other view controllers (preferences screen, log screen) brought forth by
[self presentViewController:secondary_view animated:YES completion: nil].
When certain data arrives, we want to shut down all of these secondary views summarily. We are using
[self dismissViewControllerAnimated:false completion: nil];
to do this. What we find, though, is that if the data comes in while the new view is sliding into place (not done animating), then the dismiss command has no effect, and the secondary view is still there, and in fact the app gets confused about its own state in a way that makes it appear to "hang."
Is there a better (more reliable) way to make sure that all presented view controllers are dismissed, even if they are currently animating?
My recommendation would be to present the scene using Interface Builder (storyboards) and set the Segue Identifier to a certain string with the type of presenting you're wanting done: show, show detail, modally or popover.
(see below)
Once you've done this, you can use the method: prepareForSegueWithIdentifier, where you can be assured the data exchange between the segue.destinationViewController, the View Controller you're sending the data too, and the current View Controller is performed.
(see below)
NOTE
You can perform a segue programmatically using performSegueWithIdentifier: sender:
Also, be sure to remove all the strong references to the data objects that are not being released in your current scenario. Try doing this within the Method above after you've transferred the data to the destination View Controller.
Related
My app consists of two views. The first one is a GMSMapView and the second one is used to connect to a Bluetooth device that sends coordinates.
After the Bluetooth device is connected, I use a delegate to send the information back to the map view and move a marker around. To transition between views I was previously using segues, this didn't stop the Bluetooth view controller and the data made its way like I wished to the map view.
I ran into the problem of my map view being reinitiated so I decided to use a navigation controller. Now I use a push segue to get to my second view, and pop to come back to the same instance of the first one. Great, that worked! The issue I have now is that popping the second view seems to stop it completely from running in the background like it used to. Is there a way to keep it running in the background like it did before?
What I'm currently using to pop the second view is
self.navigationController?.popViewControllerAnimated(true)
Any idea would be appreciated! Thanks!
A popped view controller does not "stop running". It is returned to you, and if you don't retain it, it is completely destroyed.
If you don't want that to happen, retain it when it is returned. You are currently ignoring the returned view controller:
self.navigationController?.popViewControllerAnimated(true)
Instead, keep a reference to it:
self.mySecondViewController =
self.navigationController?.popViewControllerAnimated(true)
Be warned, however, that this is a very unusual architecture. You will not be able to use the storyboard segue to push again, because it will push a different copy. It would be better to abandon your navigation controller architecture entirely, as it is completely unsuited to the idea of a view controller persisting after it is popped. If you want an architecture where two view controllers persist simultaneously, you would be better off using a UITabBarController — or, even better, reorganize your app completely. The notion that you need the view controller to persist after being popped is a "bad smell": it means that you have put the functionality in the wrong place. Put the functionality in a place that does persist, rather than forcing the view controller to persist in some artificial way.
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.
From an initial ViewController I've modally presented a second ViewController using a ShowDetail segue in the storyboard and a performSegueWithIdentifier: method call. The problem is when I dismiss this modal ViewController with the method dismissViewControllerAnimated: the initial ViewController is reinstantiated calling the viewDidLoad again.
I've tried using a Push segue instead of the Show Detail and the initial ViewController keeps allocated in the background as it should.
What might be going on? The initial ViewController never even calls the memory warning method.
Have you tried unwindSegues?
***** Long explanation ahead, skip to solution if you want the quick way *****
First of all, if it is a ShowDetail, it is not a modal view. Do try to see which is your case.
Modal segues can carry information backwards, but are a bit more complicated than push ones.
If you are modally presenting it, you should use Present Modally instead of a ShowDetail.
A modal presentation will always take the top view position in the stack, and Show Detail does as well, depending in how your views are set. For instance, if you have a detail view in stack, IT will be replaced rather than the stack top view.
Try choosing up to a specific segue, I particularly recommend modal assuming you need more than simple pushes (Or the Show would have closed the problem, being the equivalent to the previous deprecated push. If you only need something simple, Show is the way)
Now we've cleared this, what probably is happening is that the view is being removes since Show Detail replaces views instead of pushing them, and it has to perform init again.
***** Solution: *****
The solution then should be not to lose the view when replacing, and reinitializing it, what dismissViewControllerAnimated: does. If you use unwind segues, though, the view should be replaced BUT retained by ARC.
The following link has the best explanation all over the net about how to use it:
What are Unwind segues for and how do you use them?
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.
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/