Question

I'm trying to use a scroll view to have pagination with pages of subviews that are images that can be pinched zoomed on iOS. The pagination works, but as soon as an image is pinch-zoomed, the app crashes with EXEC_BAD_ACCESS(code=1,address=...)

I'm aware that it's a bit odd to swipe a zoomed image to pan the image and also swipe to paginate, but in the real app, the pagination will be done with a page control. Also I think it could work like the preview app. If an image is zoomed, panning will go down to the bottom of the image and then after that is reached, it goes to the next image.

Is this possible?

Here's an example:

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ScrollerViewController *viewController = [[ScrollerViewController alloc] init];
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

ScrollerViewController.m - the outer pagination view controller

- (void)viewDidLoad {

    [super viewDidLoad];

    // outer scroll view for paging with two pages
    CGRect frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
    UIScrollView *pagingScroller = [[UIScrollView alloc] initWithFrame:frame];
    pagingScroller.pagingEnabled = YES;
    pagingScroller.scrollsToTop = NO;
    pagingScroller.userInteractionEnabled = YES;
    pagingScroller.contentSize = CGSizeMake(self.view.bounds.size.width*2,self.view.bounds.size.height);

    // first page
    ImageViewController *page1 = [[ImageViewController alloc] init];
    page1.filename = @"cat.jpg";
    page1.view.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
    [pagingScroller addSubview:page1.view];

    // second page
    ImageViewController *page2 = [[ImageViewController alloc] init];
    page2.filename = @"dog.jpg";
    page2.view.frame = CGRectMake(self.view.bounds.size.width,0,self.view.bounds.size.width,self.view.bounds.size.height);
    [pagingScroller addSubview:page2.view];

    self.view = pagingScroller;
}

ImageViewController.m - the pinch-zoom image

- (void)viewDidLoad {

    [super viewDidLoad];

    // scroll view for pinch zooming
    CGRect frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
    UIScrollView *zoomScroller = [[UIScrollView alloc] initWithFrame:frame];
    zoomScroller.minimumZoomScale = 1.0;
    zoomScroller.maximumZoomScale = 5.0;
    zoomScroller.userInteractionEnabled = YES;
    zoomScroller.delegate = self;

    imageView = [[UIImageView alloc] initWithFrame:frame];
    imageView.userInteractionEnabled = YES;
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.image = [UIImage imageNamed:filename];

    [zoomScroller addSubview:imageView];

    self.view = zoomScroller;
}

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

The full project is at https://github.com/tomkincaid/ZoomScrollTest

I can test that the pinch zoom works by changing

ScrollerViewController *viewController = [[ScrollerViewController alloc] init];

to

ImageViewController *viewController = [[ImageViewController alloc] init];
viewController.filename = @"cat.jpg";
Was it helpful?

Solution

Its been quite a while that you posted your question. I bet you fixed it already yourself but I want to make sure other people can use your code.

However I downloaded your small GitHub project and found that you get the crash because you don't retain the ImageViewController's page1 and page2 in [ScrollerViewController viewDidLoad]. The views them selfs don't retain their controllers therefor the controllers get released after viewDidLoad in your case. Then when you pinch on the image scroll view it calls for its delegate but it is already deallocated.

To fix this I added two ImageViewController properties to the ScrollerViewController class and stored the controller objects there.

@interface ScrollerViewController ()

@property (strong) ImageViewController *page1;
@property (strong) ImageViewController *page2;

@end

In [ScrollerViewController viewDidLoad] I added at the end:

self.page1 = page1;
self.page2 = page2;

I hope that someone may find this information useful. Maybe you want to update your GitHub project so that it will compile and run.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top