UIView and UIViewController get deallocated, but memory is not freed - ios

I notice that in my app, sometimes when a view or view controller gets deallocated, the memory allocated for those is not freed. What could possibly be the reason for this?
I define deinit method to verify that the view and view controller do get deallocated (deinit gets called). I said sometimes because in some other cases, when I remove a view, the memory does get freed. Another thing I notice is that when I add a view, the memory usage goes up, then I remove that view (deinit is called), the memory usage stays the same, but succeeding view additions of the same view don't affect the usage.
The view is created in a method and added by View.addSubview(UIView). In the view, there is a button that invokes View.removeFromSuperView().

Try the below instead:
autoreleasepool {
View.removeFromSuperView() // not sure why you capitalized View but repeating it here just to match your code.
}
This gives iOS the chance to deallocate autorelease objects. They'll eventually autorelease anyway, like if the system needs more memory, but this allows you to force it to happen early. This SO answer explains it in more detail.

Related

popViewControllerAnimated: doesn't release view controller from memory

I have two view and second view is pushed from first view. For testing, I go to second view from first view and then I go back to first view. After that, I send nsnotification and in my second view, it receive my notification.
1) May I know why I receive notification in second view after it is pop up? For IBOutlets, I declare weak property also.
2) If it is still in memory, for other data like nsdictionary, nsstring, shall I use strong or weak property? Will those also in memory?
3) If I don't want my second view in memory totally, how shall I do?
If your second view controller is not released when you "go back" to the first view, then either
You are not really "going back" - you are accidentally creating a new first view controller and pushing it, which is unlikely; or:
You have a retain cycle in your second view controller.
I'm betting that you do have a retain cycle. You should try to track this down. You mention notifications: it is very easy to create an accidental extra retain when setting up a view controller as a notification observer, so that's probably the cause.
In particular, see my book's discussion of this topic:
If you called addObserverForName:object:​queue:usingBlock:, you will leak (under ARC) unless take elaborate precautions (such as doing the weak-strong dance in the block, to avoid a strongly retained self).

Managing instances of programmatically instantiated view controllers

If I instantiate a ViewController from my storyboard programatically, will its memory be freed once it's no longer be shown in the application?
I'm showing it as a modal.
Expanding on #Schemetrical's answer, you need to make sure there is at least one strong reference to your VC or it will be deallocated immediately.
This is a crash in the making:
func viewDidLoad()
{
childVC = self.storyboard.instantiateViewControllerWithIdentifier("childVC")
self.view.addSubview(childVC.view)
}
In the above example the current VC's content view keeps ownership of the newly created view, but nobody keeps ownership of the view controller. It gets deallocated as soon as the function returns, and the first time something tries to reference the now-deallocated VC, you crash (Say there is a button who's action points to the VC.)
If you push your VC onto the navigation stack, the navigation controller takes ownership. As soon as it's popped off the stack, it gets deallocated. If you present your VC modally, the system takes ownership for as long as it's on screen. As soon as it'd dismissed it gets deallocated.
If you want a VC to stick around after it's popped/dismissed, you need to keep a strong reference to it somewhere. You might save a reference to it in your app delegate, in a singleton, or in your app's root view controller.
As long as nothing holds strongly on the vc, it will dealloc. Once you dismiss that vc, the view releases its reference on the object and since there are no references, it will dealloc.

swift pushViewController memory

I'm using the following code to push a new view controller into the stack, the ViewController is initalised with an nib and only contains a webview, the class is completely empty.
var profileVC = GenericWebViewController()
profileVC.initWithURL(url)
navigationController.pushViewController(profileVC, animated:true)
When the view is pushed, memory usage goes up, however, when the back button is pressed, the memory level does not go down.
What should I do to get profileVC garbage collected?
Nothing ;)
Automatic reference counting automatically handles this for you
http://clang.llvm.org/docs/AutomaticReferenceCounting.html
Edit: The memory may not be going down for other reasons. Check you don't have any strong reference cycles. To be 100% sure your GenericWebViewController is being cleared from memory, override its dealloc method and make sure it's being called.
Also check out the leaks instrument

Why ARC is not deallocating memory after popViewController

I'm pushing and popping ViewControllers in UINavigationController.
I'm tracking the memory consumption of my app.
While pushing the new viewController the memory consumption is increasing gradually, but when I'm popping the same ViewController using [self.navigationController popViewControllerAnimated:NO]; the memory consumption does not decrease but the constant.
That particular viewController can be pushed and popped by user many times which can lead the high memory consumption of app in RAM.
What should I do to optimise my memory consumption?
When you dismiss a view controller (or pop it), it will be deallocated if you didn't make any strong pointers to it (that controller is retained by the navigation controller, or the presenting view controller, so you usually don't need to have a pointer to it when you create it and push or present it).
It will be be released if there are no other strong pointers to it
Try to avoid using strong properties for IBOutlets.
Consider reviewing whether you are referencing self in a block. If you do, you risk holding onto the UIViewController reference after you have popped it.
For a more in-depth review of why, check out this answer:
How do I avoid capturing self in blocks when implementing an API?
If your app design allows the user to push and pop the same view controller over and over again, you may want to look at reusing the same view controller and just updating its contents each time it's pushed.
Instead of creating and destroying it over and over, create one, set up its contents and push, when it's popped, keep it around ready to be shown again. Next time it needs to be shown, update its contents and then push it again.
I would like to say, that my last few days were spent on searching the web for my app memory problem. I was switching between 2 UIViewControllers. One of them had a scroll view which kept all subviews on it. It turned out that that UIVC loads a new scroll view without releasing the previous one. It took me several hours to realize it.
What I did was:
Looking for any kind of deadlocks inside the app, then searching for every variable that had a strong atributte and other desperate measures. But what really worked was:
#IBAction func backBB(sender: UIBarButtonItem) {
collectionView.removeFromSuperview()
self.frontView.removeFromSuperview()
eventsPhotos.removeAll(keepCapacity: false)
symbolContainerView.removeFromSuperview()
self.myScrollView.removeFromSuperview()
dismissViewControllerAnimated(true, completion: {})
}
I manually removed some views and contents. I've done it in "Back" button but you can do this in other methods like viewWillDisappear(animated: Bool).
Once I made this, my allocation chart in the developer instruments showed the memory allocation going up and down... And it was solved...
I think you get an error, when you try to pop the view controller because the navigation controller does not have a valid reference to the view controller, as it was released after you pushed it.
Nil the popover on dismiss.
[menuPopup_ dismissPopoverAnimated:YES];
menuPopup_ = nil;
Make sure your viewcontroller (A) has no reference of any other viewcontroller (B) or any object it has. Incase it has then make sure that VC-B is not referencing back VC-A. If it has some reference back to VC-A then make it a weak property. Otherwise strong retain cycle will keep the VC in memory even if its popped.
Another thing is to check wether theres any closure in your VC, check its body if it is referencing any property or method with self then make a Capture list to avoid retain cycle as "Closures are Reference Types"
Check if theres any NSNotification observer you are not releasing
Make a print call in deinit method to check wether its deallocated.
For further understanding on memory management:
https://medium.com/mackmobile/avoiding-retain-cycles-in-swift-7b08d50fe3ef
https://www.youtube.com/watch?v=GIy-qnGLpHU
You should use an unwind segue instead of popping.

Why ARC doesn't release memory when popViewControllerAnimated is called

my project use ARC, and when i have to show a view with navigation controller i do this:
ShareViewController_iPhone *share = [[ShareViewController_iPhone alloc] initWithNibName:#"ShareViewController_iPhone" bundle:nil];
[self.navigationController pushViewController:share animated:YES];
and i can see in xcode that the memory is increased of a certain value, then when i dismiss the view i do this:
[self.navigationController popViewControllerAnimated:YES];
but when the view is closed, the memory doesn't decrease, how i can do it?
When you pop the viewcontroller, it is marked for deallocation (i.e it's reference count becomes 0 unless referenced by another object). but not deallocated immediately. Deallocation as far I have seen is mostly random!
The view controller here must be retained for a while by the navigation controller itself to create the animation. The deallocation does happen immeadiately after the reference count drops to zero. Try to pop the view controller without animation (e.g. animated:NO) and see for yourself if the deallocation happens right away.
ARC will clean the memory on its own cycle (it will collect all the objects whose reference count set to "0" means who are ready for deallocation), we can't control this. It is managed by the operating system.
So when you are popping a view controller, it doesn't deallocate it from the memory immediately. It can take time depending on the other memory usage/memory availability.
One more case, you need to check if on every push the memory allocation is increased by a certain value, then there will be definitely something wrong in your code.
When you pop a ViewController and it don't release, it means have a reference cycle in your controller. You must check delegate if have, block, weak, strong reference.
Your delegate must be weak reference.
If use block. The self must be weak reference: __weak id weakSekf = self;
Hope these information will help you. :)

Resources