iOS open source smart controller push/pop lib for uinavigationcontroller? - ios

I have an application where the user can push infinitely deep into views (pushing onto nav stack). At some point, there will be a memory warning. I'd like to remove view controllers from the navigation controller and dealloc them. If the user goes back to those view controllers, I'd like to recreate the view controllers and push them back into the correct position in the stack.
Is this the right way to be thinking about this problem?
Is there an open source project that does this? It doesn't seem like an uncommon issue and I'd rather not reinvent the wheel.

There was a time where you needed to make sure that calls to viewDidLoad and viewDidUnload matched properly so that memory warnings could be handled this way. Since iOS 6 this is no longer necessary.
As it says in the documentation for viewDidUnload:
In iOS 5 and earlier, when a low-memory condition occurred and the
current view controller’s views were not needed, the system could opt
to call this method after the view controller’s view had been
released. This method was your chance to perform any final cleanup. If
your view controller stored separate references to the view or its
subviews, you could use this method to release those references. You
could also use this method to remove references to any objects that
you created to support the view but that are no longer needed now that
the view is gone. You would not use this method to release user data
or any other information that cannot be easily recreated.
In iOS 6 and later, clearing references to views and other objects in
your view controller is unnecessary.
If you're manually keeping large objects in memory, such as image or video data, then you can override didReceiveMemoryWarning to release those objects where necessary.

Related

Memory Management using viewDidUnload function

I am pretty new to IOS programming and I am working on my first app that I want to submit to app store.
That's why I made a mistake initializing all objects in viewDidLoad() function. I am using viewDidUnload() function to free the memory once the user exits from the view controller. Even though, x-code memory checking tool shows that the objects has not been deleted (the RAM usage does not decrease).
Does anyone know how to fix that or I will have to rewrite the whole code?
DeprecationAppendix
viewDidUnload
Called when the controller’s view is released from memory. (Deprecated in iOS 6.0. Views are no longer purged under low-memory conditions and so this method is never called.)
- (void)viewDidUnload
Discussion
In iOS 5 and earlier, when a low-memory condition occurred and the current view controller’s views were not needed, the system could opt to call this method after the view controller’s view had been released. This method was your chance to perform any final cleanup. If your view controller stored separate references to the view or its subviews, you could use this method to release those references. You could also use this method to remove references to any objects that you created to support the view but that are no longer needed now that the view is gone. You would not use this method to release user data or any other information that cannot be easily recreated.
In iOS 6 and later, clearing references to views and other objects in your view controller is unnecessary.
At the time this method is called, the view property is nil.
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.
viewDidUnload is deprecated function. (Link 1) It is hard to use and not called >= iOS 6.
The view controllers are automatically freed when they are not used. But if there is any reference to the view controllers, they will still reside in the memory. You should check all the strong reference to the view controller.
iOS programming has ARC now, so you dont need to worry about memory problem if you use ARC. ARC tutorial
viewDidUnload was deprecated in iOS 6. It's no longer being called. If you're using ARC, don't worry about memory management, as everything is taken care of for you. If you aren't using ARC, put your stuff in dealloc

viewDidUnload versus viewDidDisappear

I don't understand when I should implement something in viewDidUnload versus viewDidDisappear. What's the difference between the two?
For instance, I'd like to send an NSNotification when the view controller is removed from the view hierarchy. Between these two methods, does it matter where I post that notification from?
https://developer.apple.com/documentation/uikit/uiviewcontroller
This is with reference to apple's documentation:-
viewDidUnload:-
When a low-memory condition occurs and the current view controller’s views are not needed, the system may opt to remove those views from memory. This method is called after the view controller’s view has been released and is your chance to perform any final cleanup. If your view controller stores separate references to the view or its subviews, you should use this method to release those references. You can also use this method to remove references to any objects that you created to support the view but that are no longer needed now that the view is gone.
viewDidDisappear:-
Notifies the view controller that its view was removed from a view hierarchy that is everytime view dissapears or move to other view.
viewDidDisappear is called every time when the view is disappears or you go to other view and viewDidUnload is called when the controller’s view is released from memory. (Deprecated in iOS 6.0. Views are no longer purged under low-memory conditions and so this method is never called.) see the reference.

Setting up UIViewController before pushing/presenting it

In my app, I use a UINavigationController to switch between many different UIViewControllers. The only problem is that with one of my views, upon it loading, I have to do lots of customization (both data access and graphics, both of which must be done in code). When the view controller is pushed, the animation is extremely choppy, because the phone is forced to both animate the transition and set up the view at the same time.
Setting up the view after it is loaded is not an option, so is it possible to set it up (there is a method called setupViewDidLoad that has all of the necessary code in it) during allocation before it is pushed/presented?
Edit:
Let me modify my question slightly. I have found that if I present the view controller using [self presentModalViewController:animated:] instead of pushing it with the navigation controller, there is no choppiness. What is the reason for this?
Your best bet is to do this. Set up any code you need in viewWillAppear in your views .m file. If you have to access data remotely you may want to think about creating a data storage class of its own to handle and store that so it can do it whenever - even if the view isn't loaded or hasn't been loaded yet.

Allocating UIViewControllers in viewDidLoad. Was this a mistake?

A colleague and I have been designing our code so that our view controller objects are being allocated within the viewDidLoad method of our controller objects. We did this a lot and the object graph seemed to come out just fine. After a while we found the need to add another layer above our current view controller hierarchy that would own, allocate, and release our previous parent view controller.
This got me thinking about low memory warnings and view did load. Before, our views were always visible and thus wouldn't be released if a low memory warning occurred, but now there is a chance of that happening. If it does, it seems like when the views are reloaded, they will allocated new memory for new view controllers.
Will this cause widespread memory leaks? Or will the fact that we used retained declared properties save us, since the old controllers will be released automatically? Are there styles or conventions I should consider? Thanks for the help!
If you do create your view controllers in viewDidLoad, you should release them in viewDidUnload. True for pretty much any object, not just view controllers.
But I would not be surprised if you say "Wut!?" If your view controllers need to keep their state through memory warnings, then you don't want to release them. But it will be no better if you replace them with new ones that have fresh state.
It probably doesn't make sense to create view controllers in viewDidLoad. Create them in initWithNibName:bundle: (and release them in dealloc). The design pattern is that view controllers stay around, their views can come and go. If your subordinate view controllers have anything memory-intensive, release just that object in their viewDidUnload. Then on a memory warning, you will still free up a lot of memory, but all your view controllers will stay around in a low-memory usage state, retaining only a few flags, lists of indexes, etc., that they will need to restore their views when requested.
If you are explicitly releasing each view controller that is not needed any more you will not cause any memory leaks. Usually when you present a view controller the object that is doing the presenting will retain the controller for you, so you can release it if you don't need access to it anymore. But if you are using a UINavigationController and you are pushing new view controller's then you should be implementing the viewDidUnload method. This is straight from Apple's documentation:
After it is loaded into memory, a view controller’s view remains in memory until a low-memory condition occurs or the view controller itself is deallocated. In the case of a low-memory condition, the default UIViewController behavior is to release the view object stored in the view property if that view is not currently being used. However, if your custom view controller class stores outlets or pointers to any views in the view hierarchy, you must also release those references when the top-level view object is released. Failure to do so prevents those objects from being removed from memory right away and could potentially cause memory leaks later if you subsequently overwrite any pointers to them.
There are two places where your view controller should always clean up any references to view objects:
The dealloc method
The viewDidUnload method
If you use a declared property to store a reference to your view, and that property uses retain semantics, assigning a nil value to it is enough to release the view. Properties are by far the preferred way to manage your view objects because of their convenience. If you do not use properties, you must send a release message to any view that you explicitly retained before setting the corresponding pointer value to nil

When will a autorelease get released

I am looking to to develop an app where there will be "n" number of views created based on the user's interaction. If each of these views are created dynamically with autorelease, when will the view actually be released?
Lets say there are 10 views, all being dynamically created views with autorelease:
View 1 is created and added to a navigation stack, user is shown view 1
User moves to another view "View 2", View 1 is pushed off the stack and View 2 is added. Will View 1 be released here? I would not want it to be released, so should i retain it?
The problem is, i might not know how many views i am creating, so deallocating them manually might be problem, or is there a way?
I am a little confused soul here.
Thanks
You don't add views to navigation stack, you add view controllers.
When you push view controller 2, the 1st one will not get released, no. Navigation controller will always keep all it's view controllers retained until they are popped off the stack. It will only call -unloadView on non-displayed view controllers to free up some memory, but if you are creating your views inside view controllers' loadView method, everything will get recreated automatically.
You don't dealloc anything manually, you can only release it. Since navigation controller will retain any view controller you add on it's stack, you are free to release it yourself.
From the way you ask your questions, I've noticed you are missing some very basic knowledge about iOS SDK, MVC and OOP in general. I would honestly suggest you try creating a much simpler app than that chat app of yours first to learn some basics.
It will help if you post key segments of your code so we can see what you are doing. In short, if a view controller is in the navigation stack, it will be retained by the navigation controller. If it is popped off but you want to keep it, you'll need to retain it from another controller, probably the one that presents it.

Resources