Weird crash while pinching UIScrollView
Question
This issue has been driving me nuts for the past few hours. So I've got a very simple UIScrollView setup:
-UIScrollView
-UIImageView
That's it. The scrollview and imageview are generated in Storyboard. Now all I want to do is to have the ability to pinch zoom into this image. Minimum zoom is set to 1 and maximum zoom is 3. The scrollview's delegate is set to my RootViewController
In my RootViewController, I have added this function(Required to support zooming)
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return _theImageView;
}
I believe I've done everything right but whenever I pinch the scrollview, I get the great EXE_BAD_ACCESS. I've tried to look everywhere and I can't seem to find the issue. Crash dump attached below
0 libobjc.A.dylib 0x34b80f7e objc_msgSend + 22
1 UIKit 0x3516899e -[UIScrollView _getDelegateZoomView] + 70
2 UIKit 0x351908f2 -[UIScrollView _zoomScaleFromPresentationLayer:] + 22
3 UIKit 0x3523bf5a -[UIScrollViewPinchGestureRecognizer touchesBegan:withEvent:] + 102
4 UIKit 0x35102436 -[UIWindow _sendGesturesForEvent:] + 278
5 UIKit 0x351021ee -[UIWindow sendEvent:] + 82
6 UIKit 0x350e868e -[UIApplication sendEvent:] + 350
7 UIKit 0x350e7f34 _UIApplicationHandleEvent + 5820
8 GraphicsServices 0x32c85224 PurpleEventCallback + 876
What am I doing wrong?
Maybe I'm too sleepy
Solution 2
So I solved this the next morning after looking at the code with a fresh pair of eyes. I have a MainViewController
initializing and added RootViewController
to it's subview. The issue was that this was a _weak reference and ARC was dealloc-ing it.
Assigned it as a global _strong variable on MainViewController
and all was fixed.
OTHER TIPS
Had similar issue, solved it by adding the following in the dealloc of the view controller:
self.scrollView.delegate = nil;
self.scrollView = nil;
And I'm using ARC so it seems redundant, but it definitely solves the issue. I suspect that this is the cause of the issue:
@property(nonatomic,assign) id<UIScrollViewDelegate> delegate; // default nil. weak reference
From the UIScrollView.h
file
What is _theView
? If it's your UIScrollView
, then you need to do this:
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [_theView viewForZoomingInScrollView:scrollView];
}
Also, you don't necessarily need this at all. Pinch-zooming should work automatically, unless you explicitly set the scroll view's delegate; if you do this, pinch-zooming should still work automatically in iOS 5, so you would only need to implement viewForZoomingInScrollView:
for this to work in iOS 4.
You need to work out the minimum zoom scale for the scroll view. A zoom scale of one means that the content is displayed at normal size. A zoom scale below one shows the content zoomed out, while a zoom scale of greater than one shows the content zoomed in. To get the minimum zoom scale, you calculate how far you’d need to zoom out so that the image fits snugly in your scroll view’s bounds based on its width. Then you do the same based upon the image’s height. The minimum of those two resulting zoom scales will be the scroll view’s minimum zoom scale. That gives you a zoom scale where you can see the entire image when fully zoomed out.
Swift:
let scrollViewFrame = scrollView.frame
let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
let minScale = min(scaleWidth, scaleHeight);
scrollView.minimumZoomScale = minScale;
Objective-C
CGFloat scrollViewFrame = scrollView.frame
CGFloat scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
CGFloat scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
CGFloat minScale = min(scaleWidth, scaleHeight);
scrollView.minimumZoomScale = minScale;
From other projects and personal experience doing heavy GPU on the iOS (endless scroll, maximum bitmap size, etc), I've noticed that each device has it's own threshold. For past projects, I've also hardcoded the below values as the minimumZoomScale to prevent the crashes:
scale :
{
iPad : {
min : 0.8
, max : 1.6
}
, iPhone : {
min : 0.25
, max : 1.6
}
, iPhone6 : {
min : 0.3333
, max : 1.6
}
, iPhoneResizable: {
min : 1
, max : 1.6
}
}
Great tutorial for beginners: http://www.raywenderlich.com/76436/use-uiscrollview-scroll-zoom-content-swift