views:

722

answers:

2

Hi, I'm having trouble deallocating a UISCrollView that contains images. There's something wrong with my code, but I cannot understand where.

this is a snippet of my code. It basically create a loops adding a uiscrollview with an image and removing. If you run the code with instruments, no memory will be freed. I also add some check for the retainCount, with no luck at all..

here's the code

- (void)loadView {
 [super loadView];
 CGRect theRect = CGRectMake(0, 0, 320, 480);
 UIView *view = [[UIView alloc] initWithFrame:theRect];
 [view setBackgroundColor:[UIColor purpleColor] ];
 self.view = view;
 [view release];

 UIView *pippo = [[UIView alloc] initWithFrame:theRect];
 [pippo setBackgroundColor:[UIColor redColor]];
 [self.view addSubview:pippo];
 [pippo release];

 [self performSelector:@selector(scrollAdd:) withObject:nil afterDelay:2.0f];
}



-(void)scrollAdd:(id)o {
 CGRect theRect = CGRectMake(0, 0, 320, 480);
 int numero = 1;
 scroll = [[UIScrollView alloc] initWithFrame:theRect];
 [scroll setContentSize:CGSizeMake( 320*numero,1)];
 [scroll setScrollEnabled:YES];

 UIImage *img = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"koala1b" ofType:@"jpg"]];
 int dd = [img retainCount];
 UIImageView *v2 = [[UIImageView alloc] initWithFrame:theRect];
 [v2 setImage:img];
 [scroll addSubview:v2];
 dd = [v2 retainCount];
 [v2 release];
 dd = [v2 retainCount];
 dd = [img retainCount];
 [self.view addSubview:scroll];
 [img release];
 dd = [img retainCount];

 [self performSelector:@selector(scrollRemove:) withObject:nil afterDelay:2.0f];
}

-(void)scrollRemove:(id)o {
 int dd = [scroll retainCount];
 UIImageView *theV = [[scroll subviews] objectAtIndex:0];
 dd = [theV retainCount];
 [scroll removeFromSuperview];
 dd = [theV retainCount];
 [theV release];
 dd = [theV retainCount];
 dd = [scroll retainCount];
 scroll = nil;
 [self performSelector:@selector(scrollAdd:) withObject:nil afterDelay:2.0f];
}
+1  A: 

The issue is that you are releasing img when you shouldn't (which is probably being masked by the view hierarchy never being released), and you aren't releasing scroll when you should.

-(void)scrollAdd:(id)o {
 CGRect theRect = CGRectMake(0, 0, 320, 480);
 int numero = 1;
 scroll = [[UIScrollView alloc] initWithFrame:theRect];
 [scroll setContentSize:CGSizeMake( 320*numero,1)];
 [scroll setScrollEnabled:YES];

 UIImage *img = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"koala1b" ofType:@"jpg"]];
 int dd = [img retainCount];
 UIImageView *v2 = [[UIImageView alloc] initWithFrame:theRect];
 [v2 setImage:img];
 [scroll addSubview:v2];
 [v2 release];
 [self.view addSubview:scroll];
 [img release];
 dd = [img retainCount];

 [self performSelector:@selector(scrollRemove:) withObject:nil afterDelay:2.0f];
}

This should be:

-(void)scrollAdd:(id)o {
  CGRect theRect = CGRectMake(0, 0, 320, 480);
  int numero = 1;
  scroll = [[UIScrollView alloc] initWithFrame:theRect];
  [scroll setContentSize:CGSizeMake( 320*numero,1)];
  [scroll setScrollEnabled:YES];

  UIImage *img = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"koala1b" ofType:@"jpg"]];
  UIImageView *v2 = [[UIImageView alloc] initWithFrame:theRect];
  [v2 setImage:img];
  [scroll addSubview:v2];
  [v2 release];
  [self.view addSubview:scroll];

  [self performSelector:@selector(scrollRemove:) withObject:nil afterDelay:2.0f];
}

Of course if you do this you need to also make a slight change in your view removal path:

-(void)scrollRemove:(id)o {
  [scroll removeFromSuperview];
  [scroll release];
  scroll = nil;

 [self performSelector:@selector(scrollAdd:) withObject:nil afterDelay:2.0f];
}
Louis Gerbarg
+1  A: 

I've basically reached the same conclusions as @Louis, but also made some comments within the code as to what I removed and why.

- (void)loadView {
 [super loadView];
 CGRect theRect = CGRectMake(0, 0, 320, 480);
 UIView *view = [[UIView alloc] initWithFrame:theRect];
 [view setBackgroundColor:[UIColor purpleColor] ];
 self.view = view;
 [view release];

 UIView *pippo = [[UIView alloc] initWithFrame:theRect];
 [pippo setBackgroundColor:[UIColor redColor]];
 [self.view addSubview:pippo];
 [pippo release];

 [self performSelector:@selector(scrollAdd:) withObject:nil afterDelay:2.0f];
}



-(void)scrollAdd:(id)o {
     CGRect theRect = CGRectMake(0, 0, 320, 480);
     int numero = 1;
     scroll = [[UIScrollView alloc] initWithFrame:theRect];
     [scroll setContentSize:CGSizeMake( 320*numero,1)];
     [scroll setScrollEnabled:YES];

    // img is already autoreleased, you're releasing again down below
    // --- UIImage *img = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"koala1b" ofType:@"jpg"]];
    UIImageView *v2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"koala1b.jpg"]];
    v2.frame = theRect;
    //--- [v2 setImage:img];
    [scroll addSubview:v2];
    [v2 release];
    [self.view addSubview:scroll];
    // NO !; img is autoreleased from imageWithContentsOfFile
    //--- [img release];

    [self performSelector:@selector(scrollRemove:) withObject:nil afterDelay:2.0f];
}

-(void)scrollRemove:(id)o {
     //--- UIImageView *theV = [[scroll subviews] objectAtIndex:0];
     [scroll removeFromSuperview];
     // you don't own theV because you didn't create it here, or send it a retain. So NO release
     // it also appears that you think you're responsible for releasing or cleaning up
     // a view's subviews.  NO. Just call [scroll removeFromSuperview] and let scroll view
     // clean it's own resources.
     //--- [theV release];
     [scroll release];
     scroll = nil;
     [self performSelector:@selector(scrollAdd:) withObject:nil afterDelay:2.0f];
}
wkw
Thanks, your solution do not increase memory usage!It was really useful
Mauro Delrio