13

I have 2 view controller,

FirstViewController - > SecondViewController via

[self presentViewController:SVC animated:YES completion:nil];

memory graph

on SecondViewContrller when I do

[self dismissViewControllerAnimated:YES completion:nil];

enter image description here

My question is, Why is the objects not release on secondViewController after I dismiss this viewcontroller. As you can see on the graph It didn't go down after dismiss. BTW whats the best way to release/dismiss a ViewController?

[EDIT]

I NSLog a message on dealloc method on every VC, When I start from FVC->SVC->[dismiss SVC]. this is my logs

enter image description here

Bordz
  • 2,810
  • 4
  • 23
  • 27
  • did you alloc the viewcontroller properly. give your viewcontroller init alloc code – codercat Nov 29 '13 at 07:37
  • SecondViewController *SVC = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; – Bordz Nov 29 '13 at 07:39
  • 3
    You can implement the dealloc method in your second view controller and put a breakpoint in there (or an `NSLog`). ARC does not mean immediate releasing. – Marc Nov 29 '13 at 07:41
  • set property for viewcontroller – codercat Nov 29 '13 at 07:42
  • @MarcMosby It seems it did not went through dealloc method. I though ARC will take care of this. What should I do in dealloc? – Bordz Nov 29 '13 at 07:42
  • @iDev what do you mean set property for vc? – Bordz Nov 29 '13 at 07:43
  • @MarcMosby Oh! my bad! It went through dealloc method. I forgot to enable the breakpoint sorry. – Bordz Nov 29 '13 at 07:45
  • Mostly you should do nothing in there. This is a good place to unregister observers, but don't set properties to nil or stuff like that (ARC does that for you). If there is no need to dealloc your VC, then ARC won't do it. If it went through dealloc, then I'd say it's released. – Marc Nov 29 '13 at 07:45
  • @MarcMosby yeah, but I'm wondering how was memory not release after dismissing? From What I've search on, if you dismiss the VC all object/properties under it would automatically release also.. – Bordz Nov 29 '13 at 07:47
  • @MarcMosby I tried to log a message on dealloc on each FVC and SVC. when I start with FVC->SVC->[SVC dismiss] the log is these:FVC-dealloc,SVC-dealloc,FVC-dealloc – Bordz Nov 29 '13 at 08:09

6 Answers6

8

This can be pretty rough stuff. I had similar issues before. Search your code and see if you have strong or wrong references to objects.

One of my top mistakes (and what I have seen on the internet hundreds of times) are delegate properties. I wrote them like @property (nonatomic, retain) id<protocol>delegate; for quite a long time as I realized that if I do so, the delegated object does not get released. One have to use assign in this case.

Hope that help you...

Julian F. Weinert
  • 7,474
  • 7
  • 59
  • 107
  • Hi thanks for your thoughts, BUT in my case I didn't do any delegate,outlet,protocol etc. this is just a simple view controller. My point in this is to really check the memory management when dismissing VC's. – Bordz Nov 29 '13 at 08:49
2

I have made some investigation with this behavior.

FirstViewController.m

 #import "FirstViewController.h"  
 #import "SecondViewController.h"

@interface FirstViewController ()

@end

@implementation FirstViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
    // Custom initialization
}
  return self;
}

-(void)dealloc {
    NSLog(@"First Dealloc");

}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    UIButton *pressMe=[UIButton buttonWithType:UIButtonTypeCustom];
    pressMe.frame = CGRectMake(0, 0, 100, 40);
    pressMe.center = self.view.center;
    [pressMe setTitle:@"PressMe" forState:UIControlStateNormal];
    [pressMe addTarget:self action:@selector(pressMeAction:)             
    forControlEvents:UIControlEventTouchUpInside];
     [self.view addSubview:pressMe];

// Do any additional setup after loading the view.
 }

 - (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

-(void) pressMeAction:(id) sender
{
    SecondViewController *svc = [[SecondViewController alloc] init];
    [self presentViewController:svc animated:YES completion:nil];
    NSLog(@"Present Second");
}

@end

SecondViewController.m

is pretty the same except

-(void) pressDissmissButtonAction:(id) sender
{
    [self dismissViewControllerAnimated:YES completion:nil];
    NSLog(@"Dismiss Second");
}

and this is Allocation dynamics enter image description here

As you can see after pressMeButtonAction invoked secondViewController allocated and after pressDissmissButtonAction invoked secondViewController is successfully deallocated.

BUT: Most of the time it deallocated immediately, but if you present and dismiss it very quickly (twice a second or so), dellocation not fired immediately, but after a while.

I Assume that this is by design implementation of ARC deallocation procedure. Not sure.

Community
  • 1
  • 1
Eugene P
  • 554
  • 4
  • 19
  • You cannot implement the `-dealloc` method with ARC enabled – Julian F. Weinert Nov 29 '13 at 08:46
  • 6
    This is not correct. You must not invoke delloc on super when using ARC. https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/dealloc – Eugene P Nov 29 '13 at 08:48
  • does your NSlog on dealloc method on FirstVC came out? – Bordz Nov 29 '13 at 08:51
  • No it not, coz this controller is a root controller. – Eugene P Nov 29 '13 at 08:54
  • Sorry, I thought I couldn't compile with implemented `-dealloc` method – Julian F. Weinert Nov 29 '13 at 08:55
  • I tried to recreate your VC's when I dismiss the SVC, how come it'll wend through dealloc on FVC? – Bordz Nov 29 '13 at 09:07
  • @Bodz Well it depends on your needs, in my solution the FVC is root, so you can't dismiss it, if you what to check that it dealloc try to create another root controller and let this controller present both FVC and SVC. But I think this is not that you try to achieve. – Eugene P Nov 29 '13 at 09:17
0

try this ...

[self presentViewController:SVC animated:YES completion:nil];

SVC = nil;
Shaik Riyaz
  • 11,204
  • 7
  • 53
  • 70
0

After spending many hours on this, I finally found a missing piece of the puzzle: Not only do you have to set any strong references to the ViewController to nil, you also have to invalidate any timers and be aware of block retain cycles. Any time you use self in a block you create a retain cycle! Instead you should declare a variable like so

__unsafe_unretained ViewController *weakSelf = self; 

and use it instead of self in the block.

Atomix
  • 13,427
  • 9
  • 38
  • 46
  • Thanks for this info. Could you provide a screenshot for the memory chart where in it will go down once you dismiss the SecondViewController – Bordz Feb 26 '16 at 08:15
0

Check all IBOutlets in your application. There might be "strong" property assigned to them. Make them "weak". For example, an IBOulet should be like this:

@property (weak, nonatomic) IBOutlet UILabel *myLabel;

Check all delegates (if any) in your application. Every delegate should be like this:

@property (nonatomic, assign) id <yourProtocol> delegate;

Note that, it takes some amount of time for ARC to recover memory.

KSR
  • 1,699
  • 15
  • 22
0

Timers were the issue in my case. Added timer invalidate to viewWillDisappear and the view controllers were then released.