Несколько UIImageViews в UIScrollView и сбои - PullRequest
0 голосов
/ 24 декабря 2009

У меня проблема с приложением для просмотра фотографий, которое я написал.

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

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

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

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

РЕДАКТИРОВАТЬ: Это ссылка на основные файлы проекта. http://www.mediafire.com/?nztrd1yhzoo

AlbumsViewController (выдвигает отдельный «альбомный контроллер»)

 - (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];

}

}

Ответы [ 3 ]

0 голосов
/ 24 декабря 2009

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

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

Также в этой строке:

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

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

0 голосов
/ 21 января 2010

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

0 голосов
/ 24 декабря 2009

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

...