13
votes

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

6
did you alloc the viewcontroller properly. give your viewcontroller init alloc code - codercat
SecondViewController *SVC = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; - Bordz
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
set property for viewcontroller - codercat
@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

6 Answers

8
votes

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

2
votes

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.

0
votes

try this ...

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

SVC = nil;
0
votes

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.

0
votes

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.

0
votes

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