【问题标题】:Several UIImageViews in UIScrollView and crashesUIScrollView 中的几个 UIImageViews 和崩溃
【发布时间】:2009-12-23 22:53:44
【问题描述】:

我编写的照片查看应用程序有问题。

我有一个内部带有 UINavigationController 的 UITabBarController。 UINavigationController 最初显示一个 UITableView。在选择时,它会推送另一个 UIViewController(个人相册)以及 NSArray 照片。这个控制器包含一个 UIScrollView/UIPageControl,它显示了几个 UIViewControllers,其中有一个 UIImageView。

该应用程序最初运行良好。它为每个相册正确加载每个图像,您可以从导航栏返回。问题是在大约 180 张图像之后,应用程序开始抛出内存警告并最终崩溃并抛出“程序接收信号:“0”。警告:check_safe_call:无法恢复当前帧”,我认为这与内存不足有关。 这非常令人沮丧,因为我已经检查过并且没有泄漏,并且每个 dealloc 都被调用了。 dealloc 方法释放每个保留的属性并将它们设置为 nil。

如果您签入仪器,它会显示在查看每张专辑后内存使用量逐渐上升。它确实释放了一些内存,但不是全部。例如如果相册使用 1MB 显示 0.9MB 可能会被释放。

任何帮助将不胜感激。这是我发布前的最后一期。

编辑:这是基本项目文件的链接。 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];
}

相册视图控制器

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

}

}

【问题讨论】:

    标签: iphone crash uiscrollview uiimageview dealloc


    【解决方案1】:

    正确使用 ObjectAlloc Instrument,您可以准确地找出内存被使用的位置,从而找到内存泄漏的原因。

    【讨论】:

    • 我只是假设您正在泄漏,因为您说它会引发内存警告。除非内存不足,否则不会收到内存警告,而随着时间的推移内存不足的唯一方法是泄漏内存。 ;) 使用 ObjectAlloc 并使用“已创建且仍然存在”选项来找出未释放的 0.1 MB 是什么。
    • ObjectAlloc 通常可以隐藏显示元素的真实内存使用情况。要更准确地读取整体内存使用情况,您需要使用 Memory Monitor 工具。
    • 根据泄漏工具,没有泄漏,如果您在 ImageViewController 中将 NSLog 添加到 dealloc,它表明如果添加到 UIScrollView(并且可能是控制器数组),它将在图像之后被调用。内存监视器工具中的“真实内存”到底显示了什么?是主动记忆吗?如果是这种情况,我会完全感到困惑,因为它显示每个图像加载后值都会上升,但在“ImageViewController”中调用 dealloc 时几乎没有释放任何内存。你介意看看这个项目(见帖子),看看你是否能看到任何明显的东西。
    【解决方案2】:

    请务必使用 Instruments 并检查泄漏视图以确保。

    但是,如果您确定它没有泄漏:如果您加载的图像较少,这个问题是否需要更长的时间才能发生?您可能想尝试对图像进行下采样以适应更多内存,或者仅根据需要从磁盘加载它们。

    另外,在这一行:

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

    我相信autorelease 调用是不必要的,因为方法名称成语+objectWithArgument: 返回一个自动释放的对象。我不确定自动释放两次是否会在以后产生不良后果,但值得一试。试着把它拿出来看看有什么变化。

    【讨论】:

    • 根据泄漏工具没有泄漏。每个相册中的图像数量各不相同。如果您加载较少的内容,则崩溃需要更长的时间。图像已经在我们可以拍摄的范围内进行了下采样。我认为是这种情况,但是当我通过代码确保所有对象都被释放时,我还是添加了自动释放。
    【解决方案3】:

    在说服我的客户后,我设法通过使用 three20 框架解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2013-03-24
      • 1970-01-01
      • 2018-03-03
      • 1970-01-01
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多