I'm working on an iPad photo collage app that draws perhaps hundreds of UIImageView
s on the screen at once.
There is a button that lets the user "re-create", which is suppose to run a for
loop to [photo removeFromSuperview]
on all photos and then initialize a new batch, in that order.
I'm using ARC, and my console tells me that my Photo
's dealloc
method isn't being called until AFTER the next batch has been drawn, meaning I'm running into memory issues, even though I'm trying to remove the first set before adding the next set.
Is there a way to either 1) wait until all the photos have been properly dealloc'd or 2) force all the photos to dealloc immediately under ARC?
You are probably putting your image views in an autorelease pool without realizing it. You may be able to fix this by wrapping your own autorelease pool around your for-loop.
For example, I made a very simple test project with one image view and one button under my top-level view. When I tap the button, it removes the image view and creates a new one. It removes the image view by looping over the top-level view's subviews. Here's the code:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initImageView];
}
- (IBAction)redoWasTapped:(id)sender {
[self destroyImageView];
[self initImageView];
}
- (void)destroyImageView {
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
[subview removeFromSuperview];
}
}
}
- (void)initImageView {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"picture.jpg"]];
imageView.frame = CGRectInset(self.view.bounds, 100, 100);
[self.view addSubview:imageView];
}
@end
When I ran this under the Allocations instrument with “Record reference counts” enabled, I saw that each removed image view was not deallocated during destroyImageView
. Instead, it was deallocated later when the run loop called -[NSAutoreleasePool release]
.
Then I changed destroyImageView
to manage its own autorelease pool:
- (void)destroyImageView {
@autoreleasepool {
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
[subview removeFromSuperview];
}
}
}
}
When I ran it again under Instruments, I saw that each removed image view was deallocated during destroyImageView
, at the end of the @autoreleasepool
block.
ARC dealloc
s any object to which there are no more strong references. So to dealloc
something, simply set all the variables pointing to it to nil
and make sure the object is not involved in any circular reference.