Storyboard Controllers not Deallocating - iphone

My Initial View Controller of the storyboard load another view controller using performSegue:withIdentifier method which in turn loads some other controller using same performSegue:withIdentifier method.
However, neither the initial view controller nor the second view controller are deallocating. They both tend to have a reference count of 1 as seen via instruments.
I need to send user back to first controller when he logs out of application. The only way I have figured so far is to use performSegue:withIdentifier method and send the user back to initial controller.
However, it concerns me that previous controllers will not have been deallocated thus, resulting in re-creation same view controllers.
Since I need to logout a user back to first screen, I want to make sure that all previous view controllers have been deallocated.

When you perform a push or modal segue, it will not (and should not) release the view controller from which you're seguing. It needs to keep it so that when you pop/dismiss back to it, it will still be there. The exception to this rule is when using a split view controller and you use a replace segue. But that's a special case.
If you want to go back to the first scene, if you're using a navigation controller and using only push segues, you can use popToRootViewControllerAnimated. (For iOS 5 targets, I'll always use navigation controller, and hide the navigation bar if I don't want it visible, for that reason. It's convenient to be able to pop back multiple levels. It's cumbersome to achieve the same effect with modal segues.) In iOS 6, you can use an unwind segue, in which you can pop/dismiss back an arbitrary number level of scenes, for example, to return to your initial scene.

Looping with performSegue is not a good idea..
If you have to go back in your VC hierarchy, you should either use a UINavigationController with pushing/poping VCs, or presenting/dismissing a modal VC. You can combine both by modally presenting a UINavigationController.

Prior to iOS 6 A UIViewController will stay alive but its more expensive UIView will be deallocated to save memory. The UIViewController itself is pretty light compared to a UIView.
Since iOS 6 you should according to the documentation override didReceiveMemoryWarning
Docs for UIViewController:
Memory Management
Memory is a critical resource in iOS, and view controllers provide
built-in support for reducing their memory footprint at critical
times. The UIViewController class provides some automatic handling of
low-memory conditions through its didReceiveMemoryWarning method,
which releases unneeded memory.
Prior to iOS 6, when a low-memory warning occurred, the
UIViewController class purged its views if it knew it could reload or
recreate them again later. If this happens, it also calls the
viewWillUnload and viewDidUnload methods to give your code a chance to
relinquish ownership of any objects that are associated with your view
hierarchy, including objects loaded from the nib file, objects created
in your viewDidLoad method, and objects created lazily at runtime and
added to the view hierarchy. On iOS 6, views are never purged and
these methods are never called. If your view controller needs to
perform specific tasks when memory is low, it should override the
didReceiveMemoryWarning method.
As long as you manage you correctly react (depends on the iOS Version) and dealloc the view I see no problems here.

Related

iOS Storyboard Modal Segues and Memory

My apps "short" description:
Basically an interactive storybook, I have a class that sets up a audio session and audio player which every other class(ViewControllers) in my app imports and calls a function or two to set the right sound to be played each time something happens(for instance.. user reads the story). Each ViewController has it's own .m and .h classes and uses them for animations and action handling. My app is only about 60 mb's in size (audio/images/code).
Now these ViewControllers are set up in a storyboard (they are 13 now) and are modal segued from one to the next one and then programmatically dismissed to go back.
When I run my app on my iPad now, I'm starting to get memory warnings and yes Instruments is showing me that my app is adding roughly about 40 Mb's for every ViewController that I segue to.
My questions are:
Do they reside in real memory no matter what I do? (I thought I wasn't holding any strong pointers to these view controllers).
Is there an easy way for me to dismiss one controller and still use a modal segue to get to the next one?(ran into troubles trying this)
Modal Segues are probably not the way I should be doing things in my App are they?!. They looked so nice and easy for my "storybook", but now they are giving me a very rough time.
Any other tips you can give me from what I described are appreciated.
Thank you.
Yes, as long as you present it modally. The presenter view controller keeps a strong pointer to the presented view controller. What you could do here is in the viewWillDisappear: release all the images and other views that might use memory !
You could instantiate your view controller using the method instantiateViewControllerWithIdentifier: and then presentViewController:animated:completion: like you would do with any view controller
It's up to you to decide. But you could easily mimic the animation if you wanted to.
If I understood everything correctly I would go with a singleton class kinda like 'AudioEngine' which is accessible from anywhere in any class. Then I would design all my viewcontrollers in my storyboard like you did. When I need to present modally another view controller, I'll do it using the answer of your 2nd question. If I still had a memory issue, I would try to cheat and keeps always 3 view controllers (like we do with the UIScrollView's infinite scroll) that I would reuse and I'll mimic the modal presentation using UIView's animation blocks.

iPhone iOS UITabBar how to deallocate controller and have it re-initialized later?

I'm thinking of a way to respond to memory warnings generated by iOS. I got one "expensive" tab bar controller that is a good candidate for de-allocation in response to memory warning.
How would I go about marking a controller managed by UITabBar "free for deletion", but allow the user to re-initialize the controller if a user re-selects the proper UITabBar tab?
Will UITabBar take care of re-initializing a controller that was deallocated, or will this involve some sort of lazy initialization?
Do I need to write custom code for what happens when a tab is selected and the controller is nil?
UITabBarController auto manage its allocation and deallocation.
For example, when you add a UIViewController to it, the tabbarcontroller will NOT load your view (calling viewDidLoad), it will load only your class (init method). Then you can do all the heavy work on viewDidLoad.
When it receive an warning notification, TabbarController will release all your views, except the current one and will reload when user go back to a released tab.
--
sry for the bad english there.

iPhone: Good idea to dealloc and rellocate UI items when switching views?

Suppose I have 2 views. In the first view, I allocate memory to displaying many UI components such as an UILabel, UIImages, etc.
Suppose the user navigates to the next view (via UINavigationController)
Is it OK to deallocate memory assigned to displaying UI components in the first view and then initialize them again once the user goes back to the first view (in viewFirstLoad or the appropriate function)?
It seems to me if you don't do this, then memory will keep on increasing the longer the user uses your app in that particular session.
Is this not allowed? frowned upon? impossible?
It is perfectly normal and in fact, that functionality is built in standard UIViewController - when controller is not displayed its view may be released from memory and you can release all its subviews (e.g. retained through IBOutlet references) in controller's -viewDidUnload method.
When controller needs to display again it reloads its view again.
It depends. Generally, the rule of thumb is that you should free objects that you don't need. If your view is just a view, then yes, I'd release it and all of its subviews. If your view has data that was obtained through a lengthy retrieval process (e.g. a web service call), I'd probably hold onto the data somewhere so that I don't have to go back out and retrieve it when the user goes back to the first view.
To clarify a little: Apple recommends you display data specific to a view in it's -viewDidLoad method, such as setting text on labels. Then, in -viewDidUnload you should release (or nil outlets of) the view objects you setup in -viewDidLoad. It's critical you implement -viewDidLoad, as the base UIViewController code checks that it's subclass actually implements -viewDidLoad before it assumes it can unload the view (and therefore call -viewDidUnload). Failing to implement -viewDidLoad results in the controller thinking it can't recreate your view at a later time, and so it doesn't unload the view from memory. A developer I know experienced this same problem, took forever to track down.

IPhone - Which View Controller methods to use

I'm trying to figure out what logic should go into the different UIViewController methods like viewDidLoad, viewDidAppear, viewWillAppear, ...
The structure of my app is that I have a root view controller that doesn't really have a view of its own, rather it has a tab view controller and loads other view controllers into it. But in the future, it may have to load other view controllers instead of the tab bar controller depending on app logic.
My main question is, what do people usually put into the viewDidLoad, .... methods.
Currently I:
viewDidLoad - setup the tab bar controller and set its view to the view controller's own view
viewDidAppear - check if user has stored login info
if not - present with login
if so, login and get app data for first tab
I'm trying to figure out now if my logic for setting up my tab bar controller should go into loadView rather than viewDidLoad.
Any help would be great. Small examples found on the web are great, but they don't go into detail on how larger apps should be structured.
You should not implement both -viewDidLoad and -loadView; they are for different purposes. If you load a NIB, you should implement -viewDidLoad to perform any functions that need to be done after loading the NIB. Wiring up the tabbar is appropriate there if you haven't already done it in the NIB.
-loadView should be implemented if you do not use a NIB, and should construct the view.
-viewWillAppear is called immediately before you come onscreen. This is a good place to set up notification observations, update your data based on model classes that have changed since you were last on screen, and otherwise get your act together before the user sees you. You should not perform any animations here. You're not on the screen; you can't animate. I see a lot of animation glitches due to this mistake. It kind of works, but it looks weird.
-viewDidAppear is called after you come onscreen. This is where you do any entry animations (sliding up a modal, for instance; not that you should do that very often, but I was just looking at some code that did).
-viewWillDisappear is called right before you go offscreen. This is where you can do any leaving animations (including unselecting tableview cells and the like).
-viewDidDisappar is called after you're offscreen (and the animations have finished). Tear down any observations here, free up memory if possible, go to sleep as best you can.
I touch on setting up and tearing down observations here. I go into that in more depth in View controllers and notifications.
viewDidLoad will be called once per lifetime of each UIViewController's view. You put stuff in there that needs to be set up and working before the user starts interacting with the view.
viewDidAppear is called whenever the view has appeared to the user. It could potentially be called more than once. An example would be the root screen of an app using a UINavigationController to push and pop a hierarchy of views. Put stuff in there that you'd want done every time. For example, you might want to hide the UINavigationBar of the root screen, but show it for all subscreens, so you'd do the hiding of the bar here.
Therefore, you'd put your logic for setting up your UITabBarController in viewDidLoad, since it only should be done once.
Regarding your app, is there a reason why you don't just make the UITabViewController be the controller loaded by your app delegate? It seems that you have a level of indirection in your app that you may or may not need. It's probably better to simplify it now, and refactor later if you need something more complex.

iPhone viewDidAppear stops firing after loading/dismissing a modal view

I'm starting to go a little crazy with this one.
I have an iphone application with a somewhat complex view structure it is a tabbed application with either a view controller or a navigation controller on each tab.
The main controller for one tab uses the viewDidAppear callback to reload any data that has been modified since the last time it was displayed and this behaves fine in most cases. The issue I have run into is that when I navigate in subviews(within the same tab) using the standard navigation controller push/pop mechanism the viewWillAppear and viewDidAppear on the main view always fire when I navigate back to it.
However if I load a modal view controller and then dismiss it, the viewWillAppear continues to fire but the viewDidAppear stops firing.
I am almost certain that this is tied to the need to manually call these callbacks on the modal controller but I cannot find the reference info on how to do this correctly. (I only see this viewDidAppear bug on the hardware, in the simulator it works as I'd expect)
If you need further clarification let me know and thanks for any input.
Yes, this is how it works. You are better off switching to using viewWillAppear.
This has the added advantage of updating the data before the screen is redrawn.
viewDidLoad should be used for one-time setup operations:
Setting titles
Instantiating subviews, content arrays
Anything else related to the infrastructure of the view in question
After that, use viewWillAppear: to do anything related to refreshing data. You shouldn't have to call any of the viewDid/viewWill methods manually – that's handled by the innards of UIView. viewDidLoad won't fire after you dismiss a modal view controller because, more than likely, the view never unloaded. viewDidLoad fires fine when you're navigating the a view controller stack since the new views need memory, requiring other views to unload, then be reloaded when they reappear.