美文网首页
关于CGImageRelease的crash

关于CGImageRelease的crash

作者: huaweiluo | 来源:发表于2018-12-12 22:06 被阅读0次

crash描述

最近看到一段代码,使用到了CGImageCreateWithImageInRect方法对图片进行裁剪.

当这段代码第一次执行时,可能没有任何问题,但是第二次执行或者多次执行以后,发生了crash,而且很难定位.

这种情形往往是内存问题.

代码分析

UIGraphicsBeginImageContextWithOptions(CGSizeMake(view.frame.size.width, view.frame.size.height), opaque, [UIScreen mainScreen].scale);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    CGImageRefimageRef = viewImage.CGImage;

    CGRectturnRect = rect;

    CGImageRef imageRefRect =CGImageCreateWithImageInRect(imageRef, turnRect);

    UIImage*snapshotImage = [[UIImagealloc]initWithCGImage:imageRefRect];

    CGImageRelease(imageRef);/// 不需要释放,否则会造成过度释放.

    CGImageRelease(imageRefRect);

看了以上代码发现2个问题:

<1>对象imageRef,实际上是viewImage的属性CGImage,而这个属性由viewImage管理,并不需要在当前方法释放;

<2>imageRefRect是在这个方法里create的,是需要Release的;

<3>C类对象的内存管理,不是由ARC管理的,所以需要考虑手动管理内存;

问题比较容易发现,但是CGImageCreateWithImageInRect的声明里有这样一段注释:

The resulting image retains a reference to the original image, so you may

release the original image after calling this function.

这句英文还是有一定迷惑性的,我理解是这样的:这个方法返回传入image的引用,所以在调用这个方法之后,你可以释放这个image对象.英文单词用的may,意思应该是"可以"但不是必须.也就是我已经持有了,你可以释放,对我不影响.(但是我觉得他还有一句话没说,这个引用也是需要release的)(欢迎拍砖,说实话我感觉这句话挺奇怪的,如果有更合理的解释,请不吝赐教)

回到上述问题,imageRef对于方法CGImageCreateWithImageInRect就是那个original image是但是,imageRef是viewImage的属性,什么时候释放或者如何释放由viewImage管理,不需要当前方法操作.

但是imageRefRect是需要当前方法在不使用的时候release掉的.

因此这段代码里同时调用了:
CGImageRelease(imageRef);/// 不需要释放,否则会造成过度释放.

CGImageRelease(imageRefRect);那么就过度释放了.

但是并不是一定马上crash,因为imageRef的管理者,可能会延期调用release,在调用之前是不会crash的,但是当这个调用时期到来的时候就crash掉了.这就是为什么这个crash是具有不确定性的.

那么解决办法就是CGImageRelease调用一次就可以了.

另外一个问题

有人认为,imageRef和imageRefRect是一回事,

CGImageRelease 掉其中任何一个就可以,都没问题.我认为不是,分析如下:

由apple api:CGImageCreateWithImageInRect的声明可以看出,imageRef和imageRefRect的确都是对同一个对象的引用,也就是说他们指向的是同一个对象,但是意义不同.

正如上文所说,imageRef的管理者是viewImage, 引用imageRefRect的管理者才是当前方法,所以在当前方法中应该CGImageRelease掉imageRefRect.这样比较安全.

我进行了2个方面的测试验证:

<1>很简单:注释掉CGImageCreateWithImageInRect那么CGImageRelease(imageRef)会crash.

<2>如果CGImageCreateWithImageInRect传入的参数不正确,返回了0x00,CGImageRelease(imageRef)也会crash.(函数执行失败,实际上没有真正引用imageRef)

显然,imageRef和imageRefRect并不是等价的.

Demo

相关工程里的代码肯定是不方便公开的,不过我在github上传了我的Demo代码.大家可以参考.crashDemo

相关文章

网友评论

      本文标题:关于CGImageRelease的crash

      本文链接:https://www.haomeiwen.com/subject/eqhmhqtx.html