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 = 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];
}
}