I'd like to learn about memory management in Objective-C which I find not that easy because I'm fairly new at Objective-C and ARC and I'm mostly used to script languages for which I don't have to deal that much (or not at all) with memory management.
The app I'm working on is presenting a viewController (with xib file attached) from code after the press of a button. In this view controller I have several views instantiated; I record a sequence of images (photo's from the camera, saved to disk) which I convert to a movie and I have a gps tracker (mapKit) which display's a little map on screen. After all is done I can push a 'done' button which calls [self dismissViewControllerAnimated:YES completion:nil];
The viewController is animated back to my rootViewController and because I put an NSLog
message inside the dealloc
method in the viewController that is being dismissed I can confirm this viewController is being deallocated.
The problem is that I see the memory rise after the use of the app (usage consists of taking pictures and recording gps locations on a MapKit map as well as generate a movie file) to about 80 MB and this drops to about 70MB when I press 'done' so the viewController dismisses and the app returns to my rootViewController. I can present the same viewController again, use it and dismiss it, and the app will still occupy around 70MB of memory which doesn't drop. This does not really look like a memory leak to me because in that case I would expect a steady rise of memory with every instantiation and dismissal of the viewController. This isn't the case even if I have different buttons in my rootViewController which all instantiate a new and unique instance of my viewController class.
I am wondering: Is there something I should look for or is this expected behavior? Maybe the app is caching classes for future use? With memory management done right, should I be expecting an app to revert to 'virgin' memory state (in this case this would be around 4 MB) after dismissal of the only viewController that was presented?
When it comes time to dismiss a presented view controller, the preferred approach is to let the presenting view controller dismiss it. In other words, whenever possible, the same view controller that presented the view controller should also take responsibility for dismissing it.
If you are using pushviewcontroller method then to dismiss you have to use popviewcontroller method .
If the only place you reference it is when you create it above, then simply calling dismissViewController on whatever has presented it, will allow your viewcontroller to be deallocated.
If you need to find the view controller that is responsible for a particular view, the easiest thing to do is walk the responder chain. This chain is built into all iOS apps, and lets you walk from one view up to its parent view, its grandparent view, and so on, until it reaches a view controller.
If you are seeing this memory rise in Xcode and not when using instruments then the answer I have come up with is in this answer.
You can read that whole answer, it's pretty in depth. But long story short, in Xcode you are seeing the amount of memory that the OS has "given" to your app to use. This will increase any time your app tries to allocate something. It does not decrease as fast because the OS does performance guesses thinking your app may need more memory in the future. It is faster for the OS to leave that memory "given" to your app than to take it away and give it back later.
The view controller should be cleared out from memory when it is not being used by other objects (or have no strong connections to your other objects that are not yet removed from memory).
Ex.
class ViewController: UIViewController {
var secondViewController: SecondViewController?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
if identifier == "second" {
if secondViewController == nil {
secondViewController = segue.destinationViewController as? SecondViewController
} else {
println("There's still an instance of second view controller")
}
}
}
}
}
Let's say you presented the secondViewController the first time using the storyboard segue, and store it in your instance of a ViewController as a property. Then, you dismiss the secondViewController, and present again the secondViewController from ViewController, it will print "There's still an instance of second view controller" since the one you presented earlier was still being used by ViewController.
However, when secondViewController has a weak connection, (weak var secondViewController: SecondViewController
), it will never print, since from the moment the secondViewController was dismissed, it will be removed from memory and secondViewController will be nil.
EDIT:
Note: Result should be the same when using Objective-C.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With