前言

趁着版本空地,晋级到了Xcode15-Beta2本想提前体验下iOS17。本以为这次晋级Xcode能直接运行应该没什么大问题,没曾想到一运行后程序直接Crash了,Crash是在YYLabel下的YYAsyncLayer类里边。众所周知,YYLabel是由远古大神ibireme开发的YYKit下属的组件。现已多年没有适配了,可是仍然返老还童,只有部份由于Api改变导致的问题需求简略维护即可。以下就是此次问题定位与修复的全过程。

Crash定位

此次晋级后编译我司项目,直接Crash,Crash日志如下。

Xcode15Beta填坑-修复YYLabel的Crash问题

Crash是在YYTextAsyncLayer类下面的第193行代码如下:


UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, self.contentsScale);

其实第一眼看代码溃散提示就很明显了,这次Xcode15在UIGraphicsBeginImageContextWithOptions下面加了断语,如果传入的size width 或许 height其间一个为0,会直接return 回来断语。并且提示咱们晋级Api为UIGraphicsImageRenderer能够处理此问题。

本着探究的精神,我从头撤回用Xcode14.3.1编译,看为什么不会溃散,成果其实也会报Invalid size正告可是不会溃散,正告如下。

Xcode15Beta填坑-修复YYLabel的Crash问题

处理计划

咱们使用UIGraphicsImageRenderer替代老旧的UIGraphicsBeginImageContextWithOptions(其实早已标记为过时),实测即便size为 zero,UIGraphicsImageRenderer在Xcode15下仍然会渲染出一个zero size的Image,可是这毫无意义,所以咱们简略判别一下,如果是非法的size咱们直接retrun,代码如下:

从193行开始一直替换到self.contents = xxx。为止,即可处理此次问题。


if (self.bounds.size.width < 1 || self.bounds.size.height < 1) {
CGImageRef image = (__bridge_retained CGImageRef)(self.contents);
self.contents = nil;
if (image) {
CFRelease(image);
}
return;
}
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:self.bounds.size];
UIImage *image = [renderer imageWithActions:(UIGraphicsImageRendererContext *context) {
if (self.opaque) {
if (!self.backgroundColor || CGColorGetAlpha(self.backgroundColor) < 1) {
CGContextSetFillColorWithColor(context.CGContext, [UIColor whiteColor].CGColor);
[context fillRect:self.bounds];
}
if (self.backgroundColor) {
CGContextSetFillColorWithColor(context.CGContext, self.backgroundColor);
[context fillRect:self.bounds];
}
}
task.display(context.CGContext, self.bounds.size, {return NO;});
}];
self.contents = (__bridge id)(image.CGImage);

结束

以上就是Xcode15修复UIGraphicsBeginImageContextWithOptions由于加了断语导致的Crash问题。我也强烈主张各位有时间查看项目其他代码直接晋级成UIGraphicsImageRenderer的计划。如果的确没时间,要加上如下判别,避免Crash。由于我是在Debug上必崩,如果是断语问题Release纷歧定会有事,可是仍是主张大家修正一下。


if (self.size.width < 1 || self.size.height < 1) {
return nil;
}