Several UIImageViews in UIScrollView and crashes
I have a problem with a photo viewing application I've written.
I have a UITabBarController with a UINavigationController inside. The UINavigationController initially displays a UITableView. On selection it pushes another UIViewController (Individual photo album) along with an NSArray of photos. This Controller contains a UIScrollView/UIPageControl which displays several UIViewControllers in which there is a UIImageView.
The application initially works great. It loads each image correctly for each Album and you can go back from the navigation bar. The problem is after about 180 images the app starts to throw memory warnings and eventually crashes throwing "Program received signal: “0”. warning: check_safe_call: could not restore current frame" which I believe is to do with low memory. It's incredibly frustrating because I've checked and there no leaks and every dealloc is being called as it should. The dealloc methods release every retained property and set them to nil.
If you check in instruments it shows the memory usage gradually going up after every album has been viewed. It does release some memory but not all of it. e.g. if the album uses 1MB to display 0.9MB might be released.
Any help would be appreciated. This is the last issue before I release it.
EDIT: This is a link to the basic project files. http://www.mediafire.com/?nztrd1yhzoo
AlbumsViewController (pushes an individual "albumviewcontroller")
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *dictThisItem = [self.arrAlbums objectAtIndex:[indexPath row]];
NSString *strBand = [dictThisItem objectForKey:@"album"];
NSMutableArray *arrThesePhotos = [[self.arrAlbums objectAtIndex:[indexPath row]] objectForKey:@"photos"];
if (self.albumViewController == nil){
self.albumViewController = [[AlbumViewController alloc] initWithNibName:nil bundle:nil];
}
albumViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:albumViewController animated:YES];
self.albumViewController.arrPhotos = arrThesePhotos;
[albumViewController populateScroller];
}
AlbumViewController
- (void)populateScroller {
imagesScroller.pagingEnabled = YES;
imagesScroller.contentSize = CGSizeMake(imagesScroller.frame.size.width * [self.arrPhotos count], 380);
imagesScroller.showsHorizontalScrollIndicator = NO;
imagesScroller.showsVerticalScrollIndicator = NO;
imagesScroller.scrollsToTop = NO;
imagesScroller.delegate = self;
imagesScroller.backgroundColor = [UIColor blackColor];
[imagesScroller scrollRectToVisible:CGRectMake(0.0, 0.0, 320.0, 480.0) animated:NO];
pageControl.numberOfPages = [self.arrPhotos count];
pageControl.currentPage = 0;
pageControl.backgroundColor = [UIColor blackColor];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.arrPhotos count]; i++) {
CGRect frame = imagesScroller.frame;
frame.origin.x = frame.size.width * i;
frame.origin.y = 开发者_StackOverflow社区0;
NSString *strImagePath = [[self.arrPhotos objectAtIndex:i] stringByReplacingOccurrencesOfString:@"iPhone" withString:@"iPhone_thumbnail"];
ImageViewController *imageViewController = [ImageViewController alloc];
imageViewController.localImage = YES;
imageViewController.albumViewController = self;
[imageViewController initWithPhotoName:strImagePath];
[controllers addObject:imageViewController];
imageViewController.view.frame = frame;
[imagesScroller addSubview:imageViewController.view];
[imageViewController release];
}
self.viewControllers = controllers;
[controllers release];
}
ImageViewController
- (void)viewDidLoad {
self.navigationShown = NO;
Cache *cache = [[Cache alloc] init];
[cache release];
NSString *strURL = [@"http://www.marklatham.co.uk" stringByAppendingString:self.strThisPhoto];
NSString *strTmpPrefix = (self.localImage) ? @"_tmp_rockphotothumb_" : @"_tmp_rockphotolarge_";
// Cache Paths
NSArray *arrPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *strLocalPath = [[arrPaths objectAtIndex:0] stringByAppendingString:@"/"];
NSString *strPrefix = (strTmpPrefix != nil) ? strTmpPrefix : @"_tmp_rockphotolarge_";
NSMutableArray *arrImagePaths = (NSMutableArray *)[strURL componentsSeparatedByString:@"/"];
// Check cache
NSString *strEntireLocalCache = [strLocalPath stringByAppendingString:[strPrefix stringByAppendingString:[arrImagePaths objectAtIndex:[arrImagePaths count]-1]]];
if ([[NSFileManager defaultManager] fileExistsAtPath:strEntireLocalCache]){
UIImageView *imvImageView = [UIImageView alloc];
UIImage *image = [[UIImage imageWithContentsOfFile:strEntireLocalCache] autorelease];
[imvImageView initWithImage:image];
CGSize imgSize = image.size;
CGFloat fltWidth = imgSize.width;
CGFloat fltHeight = imgSize.height;
// If landscape rotate image
if (fltWidth > fltHeight){
imvImageView.frame = CGRectMake(-80.0, 80.0, 481.0, 320.0);
CGAffineTransform rotate = CGAffineTransformMakeRotation(-1.57079633);
[imvImageView setTransform:rotate];
}else{
imvImageView.frame = CGRectMake(0.0, 0.0, 320.0, 481.0);
}
[self.view addSubview:imvImageView];
[imvImageView release];
}else{
// Data URL Downloading
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSData *datImageData = [NSData dataWithContentsOfURL: [NSURL URLWithString:strURL]];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[datImageData writeToFile:strEntireLocalCache atomically:YES];
UIImageView *imvImageView = [UIImageView alloc];
UIImage *image = [[UIImage imageWithData: datImageData] autorelease];
[imvImageView initWithImage:image];
CGSize imgSize = image.size;
CGFloat fltWidth = imgSize.width;
CGFloat fltHeight = imgSize.height;
// If landscape rotate image
if (fltWidth > fltHeight){
imvImageView.frame = CGRectMake(-80.0, 80.0, 481.0, 320.0);
CGAffineTransform rotate = CGAffineTransformMakeRotation(-1.57079633);
[imvImageView setTransform:rotate];
}else{
imvImageView.frame = CGRectMake(0.0, 0.0, 320.0, 481.0);
}
[self.view addSubview:imvImageView];
[imvImageView release];
}
}
Using the ObjectAlloc Instrument properly, you can find out exactly where the memory being used and therefore find the cause of the memory leak.
Do use Instruments and check the leaks view to be sure.
But if you're sure it isn't leaking: If you load fewer images, does this problem take longer to occur? You might want to try downsampling the images in order to fit more in memory, or loading them from disk only as needed.
Also, on this line:
UIImage *image = [[UIImage imageWithContentsOfFile:strEntireLocalCache] autorelease];
I believe the autorelease
call is unnecessary, because the method name idiom +objectWithArgument:
returns an autoreleased object. I'm not sure whether autoreleasing twice can have bad consequences later on, but it's worth a shot. Try taking that out and see if anything changes.
After convincing my client I managed to get around this by going with the three20 framework.
精彩评论