43

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?

mfaani
  • 33,269
  • 19
  • 164
  • 293
Wali Haider
  • 1,202
  • 1
  • 16
  • 23
  • Does the viewController's `dealloc` get called after it is popped out. – KudoCC Jan 28 '14 at 07:06
  • @KudoCC I did not check it let me check it first – Wali Haider Jan 28 '14 at 07:12
  • yes its being call because that object is not alive after popViewController call – Wali Haider Jan 28 '14 at 07:24
  • So if `dealloc` calls, are you deallocating your resources in it? can you please show code for `dealloc` ? – NeverHopeless Jan 28 '14 at 07:26
  • i did not get you,should i need to implement dealloc method?,because i checked it in instrument that object is not alive. – Wali Haider Jan 28 '14 at 07:30
  • you should implement dealloc method only if you have resources to release. If you don't release them, they will leak. – KudoCC Jan 28 '14 at 07:34
  • still i'm facing same issue here is my code -(void)dealloc { NSArray *subViews = [self.view subviews]; for (int i = 0; i – Wali Haider Jan 28 '14 at 08:51
  • If dealloc is being called then the problem isn't your view controller. What does instruments say the memory is being used for? Look up heapshot analysis. Are you looking at live bytes or total bytes? – jrturton Jan 28 '14 at 14:07
  • @jrturton actually i'm using splitView controller,on didSelectRowAtIndex of masterViewController's table every time i'm creating a scrollView on DetailViewController and again that scrollView contains many subviews like label and textFields which is taking memory.Now when i'm going back i.e. popViewController then memory is not being release,what approach should i use.i stuck with it, even tried to manage memory without ARC i.e. -fno-objc-arc.but still i'm facing same issue. – Wali Haider Jan 29 '14 at 06:14
  • Can you show the code where you select the table cell and when you go back? – jrturton Jan 29 '14 at 07:13
  • - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { //delete last scroll view if it is there if (self.scrollView) { [self.scrollView removeFromSuperview]; self.scrollView = nil; } //call method to create View NSString *idString = [self.StepId objectAtIndex:indexPath.row]; [self createViewForTheSelectedCel:idString]; } – Wali Haider Jan 29 '14 at 07:21
  • CreateViewForSelectedCell creates scrollView add many labels and textField into that and makes that scroll view the subview of detailViewController. – Wali Haider Jan 29 '14 at 07:24
  • 4
    is your viewController is referred as delegate in any other class and delegate have strong property? – Akshay Nalawade Jan 31 '14 at 06:35
  • no its not being referred as delegate in any other class @AkshayNalawade – Wali Haider Jan 31 '14 at 06:38
  • 1
    Are you storing your navigation controllers any where? in an NSArray or NSDictionary or in any other collection. It seems to be you are maintaining a strong reference to them. – Naga Mallesh Maddali Jan 31 '14 at 11:22
  • @NagaMalleshMaddali yes i'm storing it in an array i.e self.splitViewController.viewControllers=[NSArray arrayWithObjects:self.rootNav,self.detailNav,nil]; – Wali Haider Jan 31 '14 at 12:05
  • 3
    Since array will retain those view controllers, even though you pop them they wont be released. Try to remove view controller from array when you pop view controller from navigation controller. See if this reduces your memory consumption. – Naga Mallesh Maddali Jan 31 '14 at 13:34
  • @walinaqvi did you tried my above suggestion? – Naga Mallesh Maddali Feb 05 '14 at 05:53
  • Did you compile using the analyzer? That can turn up issues sometimes. – nielsbot Feb 06 '14 at 18:50
  • You should do a test. Disable the ARC for that particular view and keep eagle eye on memory and watch the behaviour if it is same or not – Pawan Sharma Feb 07 '14 at 04:46

9 Answers9

11

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

Shardul
  • 4,266
  • 3
  • 32
  • 50
  • 3
    While correct, I don't think this is to the point. Despite the controller itself being deallocated there are times when memory usage does not decrease even with pops, like in the question. – Jonny Apr 03 '14 at 04:39
  • 1
    Check out "abandoned memory" and how to find it. It's not the same as leaks. https://developer.apple.com/library/ios/recipes/Instruments_help_articles/FindingAbandonedMemory/FindingAbandonedMemory.html – Jonny Apr 04 '14 at 01:37
  • @Jonny, as i'm using navi controller too, but i got list of pages which are handled in it, which puts lots of load on stack, which occurs crash in the end, is there any way or technique to free the stack load – Ribelyn Punk Jan 18 '17 at 07:13
4

Try to avoid using strong properties for IBOutlets.

Naga Mallesh Maddali
  • 1,005
  • 10
  • 19
  • 1
    Why? Weak outlets were relevant in iOS5, when views would get unloaded, but will not cause issues now. – jrturton Jan 28 '14 at 07:21
  • You mean there wont be any difference if we declare an IBOutlet as a strong or weak property in ARC post iOS 5? – Naga Mallesh Maddali Jan 28 '14 at 07:30
  • Interested in your point @jrturton, is this documented anywhere? Also, why would you use a strong property now instead of weak anyway? – Tim Jan 28 '14 at 14:39
  • @Jeff, Strong is the default, why do the extra? The point of weak properties was that they would be nilled out when the view was unloaded. The view doesn't get unloaded anymore, so there is no point. I don't know where this is documented. – jrturton Jan 28 '14 at 14:58
  • 4
    Apple says "Outlets should generally be `weak`." [Here's the docs](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html). – jemmons Feb 03 '14 at 01:38
  • This is outdated now. Since iOS 7, am using IBOutlets as strong and it doesn't make any difference. – Harsh Aug 26 '16 at 18:45
3

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?

Community
  • 1
  • 1
2

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.

Dave Wood
  • 13,143
  • 2
  • 59
  • 67
2

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...

Just Shadow
  • 10,860
  • 6
  • 57
  • 75
  • 5
    Although you solved it for your personal needs, that doesn't seem like a clean solution. I think there's some deeper key that needs to be figured out. – Itai Spector Jul 11 '17 at 15:35
1

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.

codercat
  • 22,873
  • 9
  • 61
  • 85
0

Nil the popover on dismiss.

[menuPopup_ dismissPopoverAnimated:YES];
menuPopup_ = nil;
GMJigar
  • 496
  • 4
  • 14
0

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:

Ammar Mujeeb
  • 1,222
  • 18
  • 21
0

You should use an unwind segue instead of popping.

CSjunkie
  • 535
  • 2
  • 8
  • 28