2009-12-23 1 views
0

У меня проблема с приложением для просмотра фотографий, которое я написал.Несколько UIImageViews в UIScrollView и сбоях

У меня есть UITabBarController с UINavigationController внутри. Сначала UINavigationController отображает UITableView. При выборе он подталкивает другой UIViewController (Индивидуальный фотоальбом) вместе с NSArray фотографий. Этот контроллер содержит UIScrollView/UIPageControl, который отображает несколько UIViewControllers, в которых есть UIImageView.

Приложение изначально отлично работает. Он загружает каждое изображение для каждого альбома, и вы можете вернуться с панели навигации. Проблема в том, что после примерно 180 изображений приложение начинает выдавать предупреждения о памяти и, в конечном счете, сбрасывает метало «Program received signal:« 0 ». Warning: check_safe_call: не удалось восстановить текущий фрейм, который, как я полагаю, связан с низкой памятью. Это невероятно разочаровывает, потому что я проверил и нет утечек, и каждый dealloc называется так, как должен. Методы dealloc освобождают каждое сохраненное свойство и устанавливают их на нуль.

Если вы проверяете инструменты, это показывает, что использование памяти постепенно увеличивается после просмотра каждого альбома. Он освобождает некоторую память, но не все. например если альбом использует 1 МБ для отображения 0,9 МБ, может быть выпущен.

Любая помощь будет оценена по достоинству. Это последний вопрос, прежде чем я его выпустил.

EDIT: Это ссылка на основные файлы проекта. http://www.mediafire.com/?nztrd1yhzoo

AlbumsViewController (толкает индивидуальный "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]; 

} 

} 

ответ

0

После того, как я убедил своего клиента, мне удалось обойти это, перейдя с каркасом три20.

0

Использование инструмента ObjectAlloc правильно, вы можете узнать, где именно используется память, и, следовательно, найти причину утечки памяти.

+0

Я просто предполагал, что вы просачивались, так как вы сказали, что это бросает предупреждения о памяти. Вы не получили бы предупреждения о памяти, если у вас не хватит памяти, и единственный способ исчерпать память с течением времени - это утечка памяти. ;) Используйте ObjectAlloc и используйте опцию «Созданный и все еще живой», чтобы узнать, что такое 0,1 МБ, которое не выпущено. –

+0

ObjectAlloc может часто скрывать истинное использование памяти для элементов отображения. Для более точного считывания общего использования памяти вам нужно обратиться к инструменту монитора памяти. –

+0

В соответствии с инструментом утечки нет утечек, и если вы добавите NSLog в dealloc в ImageViewController, он покажет, что он вызывается после изображения, если он добавлен в UIScrollView (и предположительно массив контроллеров). Что именно показывает «Реальная память» в инструменте монитора памяти? Это активная память? Если это так, я полностью смущен, так как показывает, что значение растет после загрузки каждого изображения, но вряд ли какая-либо память освобождается при вызове dealloc в «ImageViewController». Не могли бы вы взглянуть на проект (см. Сообщение), чтобы увидеть, видите ли вы что-нибудь очевидное. –

0

Используйте инструменты и проверяйте вид утечки, чтобы быть уверенным.

Но если вы уверены, что это не утечка: если вы загружаете меньше изображений, эта проблема занимает больше времени? Возможно, вы захотите попробовать понизить дискретизацию изображений, чтобы больше поместиться в памяти или загрузить их с диска только по мере необходимости.

Кроме того, на этой линии:

UIImage *image = [[UIImage imageWithContentsOfFile:strEntireLocalCache] autorelease];

Я считаю, что autorelease вызов не является необходимым, так как название метода идиома +objectWithArgument: возвращает autoreleased объект. Я не уверен, может ли автореализацию дважды иметь плохие последствия позже, но это стоит того. Попытайтесь принять это и посмотреть, что-нибудь изменится.

+0

В соответствии с инструментом утечки нет утечек. Количество изображений в каждом альбоме меняется. Если вы загружаете меньше из них, для краха требуется больше времени. Изображения уже были уменьшены, насколько мы можем их принять. Я думал, что это так, но когда я проходил через код, гарантирующий, что все объекты были выпущены, я добавил autorelease в любом случае. –