confused regarding uiviewcontroller memory management and passing data between them - ios

I am new to iOS programming, i read the view controller programming guide but some things are still unclear to me
View of a viewcontroller is destroyed but viewcontroller remains, there nothing specified regarding if I my self want to destroy any viewcontroller or I just missed it. VC guide says iOS destroy VC when memory start getting short for other resources and same goes for VC's view right? Need to understand memory management of VC, please read my second point.
In a uinavigationcontroller i have a tableviewcontroller which display list of my friends, on selecting any of my friend i am pushing another VC of chat. The problem is every time on selecting a friend do i have to create a new instance of chat VC? how this chat VC will be unique for every friend i am trying to chat with? I am also saving messages in DB so who ever friend window open or close messages shows up, user don't get a blank view. Is it possible only one instant of chat VC is used for every friend uniquely(means only message of particular friend show and send to him to whom i am trying to chat). I think this problem is related to passing data between viewcontrollers but i am confused.
I hope i have clearly define what i am confused in. Please ignore any silly mistakes.
Thank you.

Answer to your queries -
View of a viewcontroller is destroyed but view controller remains
According to UIViewController guide -
It is responsible for creating those views and for relinquishing ownership of them at the appropriate times, including during low-memory conditions and when the view controller itself is released.
So we need to take the ownership to release a view controller.
Also The UIViewController class provides some automatic handling of low-memory conditions through its didReceiveMemoryWarning method, which releases unneeded memory.
In your Scenario-
TableView -> on click of cell push next view -> now pop this view to go back to table view(here memory got release) -> in table view again -> on click of cell a new view controller is pushed.
In this way it handles memory. If in a hierarchy we are pushing some views like -
VC1 -> VC2 > VC3 -> VC4
Now in this scenario navigation controller keeps instances of all these view controller, as navigation controller gives us flexibility of moving backward. And as soon as we go back that view controller is removed from stack and memory allocated to that is freed.
Syntax used -
Push a view controller -
[self.navigationController pushViewController:myViewController animated:YES];
[myViewController release];//at the time of push we add this release statement.
Now when we do a pop, its dealloc method is called and this is removed from the stack.
[self.navigationController popViewControllerAnimated:YES];//That view is release from navigation stack
Hope this clears your doubt.
Checkout this developer page for more details - http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

Related

presentModalViewController vs pushviewcontroller memory cosumption

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.

Viewcontroller stack understanding issue

I got some serious problems understanding the viewcontroller stack.
When will my app use a stack to save the previous viewcontrollers? Only if I use a navigation viewcontroller or anytime I use normal viewcontrollers and segue modally between them?
So I was just wondering if I use some sort of chained routine for example, like going from vc 1 to vc 2 and from vc 2 back to vc 1. No navigation controller, just modal segues, no unwinding.
Does my app got performance issues because of a stack (which will grow everytime I go around) or doesn't it make any difference?
----updated
So basicly this is my problem. If I went through the routine of the app, the views get stacked everytime I do a transtition.
UINavigationController will retain any controller you push onto it's navigation stack until you pop it back off.
Any UIViewController will retain a controller it presents modally until that child controller is dismissed.
In either case every controller will at a minimum consume some memory until you remove it. Apps which construct ever expanding stacks of controllers are likely to encounter a number of issues including:
you will eventually run out of memory, how fast depends on how much memory each controller uses.
you may see unexpected side effects if many controllers in the background react to the same event.
users may become confused if they change state in an instance of controller 'A', push an instance of controller 'B' on top of it, and then "return" to a second instance of 'A' added to the top of the state. Since they're looking at a new controller and view whatever selection, scroll position, user input, or other state they set on the previous instance may be lost.
developers, including you, may come to dread touching this app.
I suspect that everyone will have a better experience if you view controller management matches whatever visual metaphor you are presenting to the user.

Should a UIViewController be deallocated when it performs a Push Segue

I have a LoginViewController (UIViewController) that when all the criteria is met and the user hits the Login button, a storyboard segue is run that pushes the ProfileViewController (UIViewController). When this happens, I have a log statement in my LoginViewController's dealloc method to see if it is called and to my disappointment it is never called. My question is whether or not it is supposed to be called? Also, when I log in, sometimes I get a "Received memory warning" and sometimes I do not which I find strange because I am taking the exact same steps in both cases and yet i get a memory warning one time and not with the other.
Anyone can shine some light on this that would be great!
Thanks.
UINavigationController maintains a stack of view controllers. You start with one element, a LoginViewController, on that stack. When you push a ProfileViewController, you now have two elements on the stack. The LoginViewController can't be deallocated until it is removed from the stack.
If you want the ProfileViewController to replace the LoginViewController on the navigation controller's stack, you can write a custom segue class to implement that behavior. See this Q&A.
(You might think you could use the “Replace” or “Show Detail (e.g. Replace)” segue type in your storyboard, but those only work if you are using a UISplitViewController.)
With ARC enabled, when a object is not referenced, it will be released.
In order to display view from ProfileViewController, you instantiate a object of it in LoginViewController, and that's how you still can see the profile view after it is presented. If LoginViewController instance is released, the profile view will also get released(assume no one else references it). For the same reason, the LoginViewController instance is not released because another object is holding a reference to it. Say your views are presented in Window -> ProfileViewController -> ProfileViewController, it's the window that keeps ProfileViewController instance from being released.
If you have two views as I assumed so far, the memory warning should be from somewhere else. Two views cannot cause the issue.

Skipping view controllers in a UINavigationController stack

Is it bad practice to skip view controllers in a navigation stack?
In my example I have a UINavigationController (which is being presented modally) with three UIViewControllers (firstViewController, secondViewController and thirdViewController), most of the time the user will be accessing firstViewController, maybe tapping a row which will then load secondViewController and so on, but what if in some circumstances I want to load the second or third view controllers immediately but still keep the first view controller in the stack, so that the user can still go back to the firstViewController.
I can do this but it doesn't feel right - is this something I should avoid doing?
Yes, it's called deep-linking, and it's perfectly fine. It's quite commonly done for things like coming from an external URL or push notification.

Proper way of unloading/reloading a View Controller

I am new to iOS and wondering how to properly implement view controller unloading/reloading.
Right now my app has a NavigationController with a MainMenuViewController (custom view controller) set up as root view controller. During the course of app lifetime, new ViewControllers are pushed/popped on the Navigation Controller. This works fine, the appropriate ViewControllers are initiated (from NIBs) the first time they are pushed to the stack.
However, I now want to unload one particular ViewController when it is popped, then reload it automatically when it is pushed again.
I have added a [self release] to that ViewControllers viewDidDisappear: and it unloads, but when i try to push the view again, i get a message sent to dealloc'ed instance error and crash. Therefore, my questions are:
Is that a proper way to unload a popped ViewController?
How to check if a given ViewController is loaded or not?
How to force a reload? With loadWithNib:, then push onto navigation stack?
Regards,
Peter
Welcome to iOS programming. Your crash is a memory management issue. It may take you a bit to get the hang of it but memory management gets way easier if you just follow one rule:
an object needs to release anything it retains (alloc is equivalent to retain)
In this case, your view controller is releasing itself and it definitely did not retain itself. Here's how the sequence works with a navigation controller:
The navigation controller is initialized with a root view controller (the first one on its stack). Lets call this firstViewController
A user action tells firstViewController to initialize secondViewController and push it onto the navigation controller. In most cases, firstViewController will release the instance of secondViewController after pushing it. At this point, firstVC is done with secondVC. The navigation controller is now retaining secondVC
User touches the back button on the navigation bar of secondVC. The navigation controller will pop secondVC from the stack and release it. As long as no other object is retaining it, secondVC will get be dealloc'ed.
Now user is back in firstVC. They can do the same user action which will init and push a new instance of secondVC.
Hope that helps a bit.
I'd also recommend you (re)read the Apple docs and look at the sample code referenced in the framework docs.
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html

Resources