2

I have an app which has been extensively tested with iOS 6 and works well, while on iOS 7 it crashes almost always (but not 100% times) with an Thread 1: EXC_BAD_ACCESS error in the main, without much to trace. I am completely clueless of its whereabouts. I believe something in my code is not compatible with the core iOS methods.

The best I could identify is, upon commenting the following part of the code everything runs well.

UIGraphicsBeginImageContext(coverView.bounds.size);
[coverView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *coverImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[UIImageJPEGRepresentation(coverImage, 0.8f) writeToFile:coverFilePath atomically:YES];

//Create thumbnail of cover image
CGSize size = CGSizeMake(116.0f, 152.0f);
UIGraphicsBeginImageContext(size);
[coverImage drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
coverImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[UIImageJPEGRepresentation(coverImage, 0.8f) writeToFile:coverThumbnailFilePath atomically:YES];

Can anyone suggest me where I should go debugging next? Kindly note that the same App works fantastic in iOS 6 and this bug is very much iOS 7 specific.

EDIT: The zombie stack trace is attached: I could not make use of it much so far, but might be useful for expert eyes :)

enter image description here

Thanks in advance,

Nikhil

Nikhil J Joshi
  • 1,177
  • 2
  • 12
  • 25
  • 1
    Did you turn on exception breakpoints? I think not because you are talking about a crash in main. Turn them on (there are many guides here and on google) and then you will find a more specific line. – borrrden Nov 11 '13 at 10:10
  • Go to `Breakpoint Navigator`, tap plus sign and `Add Exception breakpoint` and select `Exception on Throw`. Then build and run and paste here more specific log. Then we will be able to help you. – Tomasz Szulc Nov 11 '13 at 10:13
  • I have them turned on, but they do not catch anything :(. The crash seems in memory. I suspect I am referring something I (read ARC) released before somewhere. – Nikhil J Joshi Nov 11 '13 at 10:14
  • Please show us `coverThumbnailFilePath` also. When breakpoint is set `On Throw` you should have selected line when app crashes. You doing something wrong. Please paste log when app crashes. This breakpoint great catch `EXC_BAD_ACCESS` crashes. – Tomasz Szulc Nov 11 '13 at 10:15
  • @TomaszSzulc, I have `All Exceptions` turned on. Still no luck. I will post the coverThumbnailFilePath shortly, but surprisingly the crash occurs even when everything is commented but the first two lines, i.e. `UIGraphicsBeginImageContext(coverView.bounds.size); [coverView.layer renderInContext:UIGraphicsGetCurrentContext()];` ... I think something's wrong with either UIGraphics or my use of it. – Nikhil J Joshi Nov 11 '13 at 10:18
  • Check before rendering if `.layer` isn't `nil`. And check if `coverView.bounds.size` isn't equals `(0,0)`. – Tomasz Szulc Nov 11 '13 at 10:19
  • checked no help. It crashes even when coverView has good size and a layer :(.... also, all of this works well with iOS 6. The crash is iOS 7 specific. – Nikhil J Joshi Nov 11 '13 at 10:28
  • is your code part of an custom `UIView` within a view controller? I had similar issues with transfering from iOS 6 to 7 when my custom `UIView` was initiated with starting the view controller. in that early stage the UIView was expecting data from the view controller which wasn't available and crashed. – JFS Nov 11 '13 at 10:30
  • Actually my proposal would be to make sure that all necessary data are available to the view when it gets initiated. prevent code getting executed to early necessary for the `UIView`. – JFS Nov 11 '13 at 10:39
  • @JFS, I always do lazy instantiation whenever possible. Though I will double check. Thanks :) – Nikhil J Joshi Nov 11 '13 at 11:40
  • It looks like you are trying to grab a screenshot. Things have changed in iOS7 - I'm too lazy to write an answer, but this SO link should help http://stackoverflow.com/q/18956611/41116 – Abizern Nov 11 '13 at 14:07
  • @Abizern Thanks for the reference. I tried it with no luck. However, one interesting thing is if I change the `afterScreenUpdate:` from `YES` to `NO` the problem is gone. Of course I want the screen shot to be taken after I updated the screen – Nikhil J Joshi Nov 11 '13 at 14:18

3 Answers3

6

OK, Finally I got it working. That was a nice learning experience overall :).

Actually the very nature of "EXE_BAD_ACCESS" did hint towards bad memory management, i.e. I was requesting access to something non-existent. Unfortunately, (or quite logically, which I missed earlier) leaks would not find it. But they were caught when I profiled my app for zombies.

The problem occurred due to the method

   [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];   // iOS 7

or equivalently in iOS 6

   [self.layer renderInContext:UIGraphicsGetCurrentContext()];

The sequence of my app progress was something like this:

   render view -> update a few things -> request a screenshot be taken on update
   -> update the view -> return to previous view (releasing this one)

Now, because I demanded the screen shots be taken upon update, these methods waited till the view update occurs. However, immediately after the update I was releasing the superview. And hence these methods (after waiting for the update) called this view after it was released.

Now, I don't know if this is Apple's iOS bug or my poor understanding of it. But now, I don't release the superview immediately upon view update and everything works fine :).

Thanks guys for your help. Let me know if I am doing something odd here and this behavior can be prevented in a more efficient way.

best, Nikhil

Nikhil J Joshi
  • 1,177
  • 2
  • 12
  • 25
1

If your UIView's height is nearly zero(such as 0.1), drawViewHierarchyInRect: afterScreenUpdates: will crash. So check the size before you call it.

PS: This only happens on iOS 7

YangXiaoyu
  • 775
  • 4
  • 10
0

Got few similar problems with iOS7, due to autolayout issues (my issues). Be sure that the size exist and is valid, for example a size with 0,0, can't create a valid graphics context.
I also add a method that you can us as a category on UIView to get screenshot of a particular view. If on iOS6 or lower it uses the well know -renderInContext:, if on iOS7 it uses the new -drawViewHierarchyInRect:: really faster than the first, se if you get crashes also using that.

- (UIImage *) imageByRenderingViewOpaque:(BOOL) yesOrNO {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, yesOrNO, 0);

    if ([self respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
        [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    }
    else {
        [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    }
    UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultingImage;
}
Andrea
  • 26,120
  • 10
  • 85
  • 131