【问题标题】:Problem releasing UIImageView after adding to UIScrollView添加到 UIScrollView 后释放 UIImageView 的问题
【发布时间】:2011-01-31 00:45:06
【问题描述】:

我遇到了与 UIImageView 相关的内存问题。将此视图添加到我的 UIScrollView 后,如果我尝试释放 UIImageView 应用程序崩溃。根据堆栈跟踪,在调用 [UIImageView dealloc] 之后调用了 [UIImageView stopAnimating]。但是,如果我不释放视图,则内存永远不会释放,并且我已经确认在解除分配后视图上仍有额外的保留调用......这导致我的总分配快速攀升并最终导致应用程序崩溃多次加载视图后。我不确定我在这里做错了什么......我不知道在 UIImageView 发布后试图访问它的原因是什么。我已经在下面包含了相关的标头和实现代码(我使用的是 Three20 框架,如果这与它有任何关系......另外,AppScrollView 只是一个 UIScrollView,它将 touchesEnded 事件转发给下一个响应者):

标题:

@interface PhotoHiResPreviewController : TTViewController <UIScrollViewDelegate> {

    NSString* imageURL;
    UIImage* hiResImage;
    UIImageView* imageView;
    UIView* mainView;
    AppScrollView* mainScrollView;
}

@property (nonatomic, retain) NSString* imageURL;
@property (nonatomic, retain) NSString* imageShortURL;
@property (nonatomic, retain) UIImage* hiResImage;
@property (nonatomic, retain) UIImageView* imageView;

- (id)initWithImageURL:(NSString*)imageTTURL;

实施:

@implementation PhotoHiResPreviewController

@synthesize imageURL, hiResImage, imageView;


- (id)initWithImageURL:(NSString*)imageTTURL {

    if (self = [super init]) {

        hiResImage = nil;

        NSString *documentsDirectory = [NSString stringWithString:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
        [self setImageURL:[NSString stringWithFormat:@"%@/%@.jpg", documentsDirectory, imageTTURL]];
    }
    return self;
}

- (void)loadView {

    [super loadView];

    // Initialize the scroll view   
    hiResImage = [UIImage imageWithContentsOfFile:self.imageURL];
    CGSize photoSize = [hiResImage size];
    mainScrollView = [[AppScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    mainScrollView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
    mainScrollView.backgroundColor = [UIColor blackColor];
    mainScrollView.contentSize = photoSize;
    mainScrollView.contentMode = UIViewContentModeScaleAspectFit;
    mainScrollView.delegate = self;

    // Create the image view and add it to the scrollview.
    UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, photoSize.width, photoSize.height)];
    tempImageView.contentMode = UIViewContentModeCenter;
    [tempImageView setImage:hiResImage];
    self.imageView = tempImageView;
    [tempImageView release];    
    [mainScrollView addSubview:imageView];

    // Configure zooming.
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    CGFloat widthRatio = screenSize.width / photoSize.width;
    CGFloat heightRatio = screenSize.height / photoSize.height;
    CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
    mainScrollView.maximumZoomScale = 3.0;
    mainScrollView.minimumZoomScale = initialZoom;
    mainScrollView.zoomScale = initialZoom;
    mainScrollView.bouncesZoom = YES;

    mainView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    mainView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
    mainView.backgroundColor = [UIColor blackColor];
    mainView.contentMode = UIViewContentModeScaleAspectFit;
    [mainView addSubview:mainScrollView];   

    // Add to view  
    self.view = mainView;
    [imageView release];
    [mainScrollView release];   
    [mainView release];
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return imageView;
}

- (void)dealloc {

    mainScrollView.delegate = nil;
    TT_RELEASE_SAFELY(imageURL);
    TT_RELEASE_SAFELY(hiResImage);
    [super dealloc];
}

我不确定如何解决这个问题。如果我在 loadView 方法的末尾删除对 [imageView release] 的调用,一切正常……但我有大量分配,很快就会爬到一个临界点。但是,如果我确实释放了它,那么 [UIImageView stopAnimating] 调用会在视图被释放后使应用程序崩溃。

感谢您的帮助!这几天我一直在用头撞这个。 :-P

干杯, 约西亚

【问题讨论】:

    标签: iphone memory-management uiimageview uiimage three20


    【解决方案1】:

    将 imageView 的释放移动到您设置它的位置之前。这样,您在更改 imageView 指针指向的位置之前释放对象:

    // Create the image view and add it to the scrollview.
    UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, photoSize.width, photoSize.height)];
    tempImageView.contentMode = UIViewContentModeCenter;
    [tempImageView setImage:hiResImage];
    // release old object
    [imageView release];
    // set the pointer to point at a new object
    self.imageView = tempImageView;
    [tempImageView release];    
    [mainScrollView addSubview:imageView];
    

    然后在释放其他对象的方法的底部,删除该行:

    [imageView release];
    

    【讨论】:

      【解决方案2】:

      理想情况下,类级别的变量应该在类的 dealloc() 方法中释放

      看起来 imgView 是一个类级别的变量,您在方法调用结束时释放它。

      如果你想在方法结束时释放一个变量——它应该是一个方法级别的变量。因此,在您的情况下,请尝试使 imgView 成为方法级别的变量。那么你应该可以在方法结束时释放它而没有任何问题

      【讨论】:

      • 我实际上已经尝试在 dealloc 调用中释放它,结果相同。我将它设为类级变量,以便在方法中引用它 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return imageView;我还尝试将 tempImageView 添加到 mainScrollView 并为其设置一个特定的标签,我可以在 viewForZoomingInScrollView 中使用它(我只是返回 [mainScrollView viewWithTag:(the tag #)])。不过,当导航回上一个控制器时,我仍然会收到对 [UIImageView stopAnimating] 的调用...
      【解决方案3】:

      为什么要创建临时视图?您是否不止一次致电loadView

      self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, photoSize.width, photoSize.height)];
      [self.imageView setContentMode:UIViewContentModeCenter];
      [self.imageView setImage:hiResImage];
      [mainScrollView addSubview:self.imageView];
      [self.imageView release]
      

      或者在dealloc 中释放它,因为它是一个实例变量? addSubview 保留你的 UIImageView,所以如果它因为对象不存在而崩溃会很奇怪。你试过设置断点吗?

      【讨论】:

        猜你喜欢
        • 2011-09-24
        • 2015-06-29
        • 1970-01-01
        • 2023-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多