【问题标题】:App crashes when I rotate phone for the first time第一次旋转手机时应用程序崩溃
【发布时间】:2010-08-20 17:12:47
【问题描述】:

应用程序仅在我第一次旋转手机时崩溃 (EXC_BAD_ACCESS)。在它所有的肉汁之后的任何时候。它也只会在设备上崩溃。模拟器一切都很好。

#import "ImageViewController.h"
#define degreesToRadian(x) (M_PI * (x) / 180.0)
#define ZOOM_VIEW_TAG 100
#define ZOOM_STEP 1.5

@interface ImageViewController (UtilityMethods)
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center;
@end

@implementation ImageViewController
@synthesize imageView,url, enableLandscapeOrientation;

/*
 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        // Custom initialization
    }
    return self;
}
*/


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    // set up main scroll view
    imageScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
    [imageScrollView setBackgroundColor:[UIColor blackColor]];
    [imageScrollView setDelegate:self];
    [imageScrollView setBouncesZoom:YES];
    [[self view] addSubview:imageScrollView];

    // add touch-sensitive image view to the scroll view
    imageView = [[AsyncImageView alloc]initWithFrame:[self.view bounds]];
    if (enableLandscapeOrientation) {
        imageView.showGhost = YES;
    }
    [imageView loadImageFromURL:self.url];
    [imageView setTag:ZOOM_VIEW_TAG];
    [imageView setUserInteractionEnabled:YES];
    [imageScrollView setContentSize:[imageView frame].size];
    [imageScrollView addSubview:imageView];
    [imageView release];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
    UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
    UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTap:)];

    [doubleTap setNumberOfTapsRequired:2];
    [twoFingerTap setNumberOfTouchesRequired:2];

    [imageView addGestureRecognizer:singleTap];
    [imageView addGestureRecognizer:doubleTap];
    [imageView addGestureRecognizer:twoFingerTap];

    [singleTap release];
    [doubleTap release];
    [twoFingerTap release];

    // calculate minimum scale to perfectly fit image width, and begin at that scale
    float minimumScale = [imageScrollView frame].size.width  / [imageView frame].size.width;
    [imageScrollView setMinimumZoomScale:minimumScale];
    [imageScrollView setMaximumZoomScale:4.0f];
    //[imageScrollView setZoomScale:minimumScale];

    //[imageScrollView setMinimumZoomScale:0.5f];
    //[imageScrollView setMaximumZoomScale:2.0f];



    //[self.imageView loadImageFromURL:self.url];
}



// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||interfaceOrientation == UIInterfaceOrientationLandscapeRight) {

        imageScrollView.frame = CGRectMake(0,0,480,300); //self.view.bounds;
        imageView.frame = CGRectMake(0,0,480,300); //self.view.bounds;
    }
    else {
        imageScrollView.frame = CGRectMake(0,0,320,460); 
        imageView.frame = CGRectMake(0,0,320,460); 
    }


    //return (interfaceOrientation == UIInterfaceOrientationPortrait);
    if (enableLandscapeOrientation) {
        [[self navigationController] setNavigationBarHidden:UIInterfaceOrientationIsLandscape(interfaceOrientation) animated:YES];
        return YES;
    }
    else {
        return NO;
    }
}


- (void)dealloc {
    [imageView release];imageView=nil;
    [url release];url=nil;
    [super dealloc];
}

#pragma mark UIScrollViewDelegate methods

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}

/************************************** NOTE **************************************/
/* The following delegate method works around a known bug in zoomToRect:animated: */
/* In the next release after 3.0 this workaround will no longer be necessary      */
/**********************************************************************************/
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
    [scrollView setZoomScale:scale+0.01 animated:NO];
    [scrollView setZoomScale:scale animated:NO];
}

#pragma mark Utility methods

- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {

    CGRect zoomRect;

    // the zoom rect is in the content view's coordinates. 
    //    At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
    //    As the zoom scale decreases, so more content is visible, the size of the rect grows.
    zoomRect.size.height = [imageScrollView frame].size.height / scale;
    zoomRect.size.width  = [imageScrollView frame].size.width  / scale;

    // choose an origin so as to get the right center.
    zoomRect.origin.x    = center.x - (zoomRect.size.width  / 2.0);
    zoomRect.origin.y    = center.y - (zoomRect.size.height / 2.0);

    return zoomRect;
}

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
    // single tap does nothing for now
}

- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
    // double tap zooms in
    float newScale = [imageScrollView zoomScale] * ZOOM_STEP;
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
    [imageScrollView zoomToRect:zoomRect animated:YES];
}

- (void)handleTwoFingerTap:(UIGestureRecognizer *)gestureRecognizer {
    // two-finger tap zooms out
    float newScale = [imageScrollView zoomScale] / ZOOM_STEP;
    CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
    [imageScrollView zoomToRect:zoomRect animated:YES];
}




@end

【问题讨论】:

  • 并发布初始化 imageView 和 imageScrollView 的位置
  • 已发布完整代码。 crash 在崩溃日志中,除了 EXC_BAD_ACCESS 没有可读数据
  • 不是答案,但 viewDidLoad 中的 [imageView release]; 是错误,因为您还在 dealloc 中调用 [imageView release];imageScrollView 也被泄露了。
  • 你应该在 viewDidUnload 和 dealloc 中释放 imageScrollView。前者是因为您在 viewDidLoad 中创建它,后者是因为不会调用 viewDidUnload,除非在 ImageViewController 的生命周期内卸载视图。重要提示:当您在 viewDidUnload 中释放它时,请将其设置为 nil,否则在 dealloc 中的释放可能会在无效引用上调用释放(如果已调用 viewDidUnload)。

标签: iphone objective-c cocoa-touch memory uiview


【解决方案1】:

viewDidLoad 中分配imageView,最后释放它,所以imageView 的保留计数为0。imageView 已释放,这就是为什么你会尽快收到EXC_BAD_ACCESS因为您想下次访问imageView。你把 [imageView dealloc] 放在你的 viewDidLoad 方法之外,一切都应该正常工作。

我还注意到另一件事:您忘记在 -(void)dealloc 中释放滚动视图。

【讨论】:

  • 所以基本上不要在 dealloc() 中释放 imageView,因为我已经在 viewDidLoad 中释放了它?
  • 你只能在 dealloc() 中释放 imageView。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多