Skip to content

UIGraphicsBeginImageContext Deprecated #984

Open
@zhuwo

Description

@zhuwo

大佬,我们这边使用了您的YYText,发现在iOS 17上运行会崩溃,触发了系统的断言:
UIGraphicsBeginImageContext() failed to allocate CGBitampContext: size={382, 0}, scale=3.000000, bitmapInfo=0x2002. Use UIGraphicsImageRenderer to avoid this assert.

查了下 api,发现UIGraphicsBeginImageContext在iOS 17上已经deprecated了,

image

大佬是否需要更新下

Activity

w1090485608

w1090485608 commented on Jun 15, 2023

@w1090485608


UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, self.contentsScale);
CGContextRef context = UIGraphicsGetCurrentContext();
if (self.opaque) {
CGSize size = self.bounds.size;
size.width *= self.contentsScale;
size.height *= self.contentsScale;
CGContextSaveGState(context); {
if (!self.backgroundColor || CGColorGetAlpha(self.backgroundColor) < 1) {
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextAddRect(context, CGRectMake(0, 0, size.width, size.height));
CGContextFillPath(context);
}
if (self.backgroundColor) {
CGContextSetFillColorWithColor(context, self.backgroundColor);
CGContextAddRect(context, CGRectMake(0, 0, size.width, size.height));
CGContextFillPath(context);
}
} CGContextRestoreGState(context);
}
task.display(context, self.bounds.size, ^{return NO;});
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.contents = (__bridge id)(image.CGImage);

替换为
UIGraphicsImageRendererFormat *format = [[UIGraphicsImageRendererFormat alloc] init];
format.opaque = self.opaque;
format.scale = self.contentsScale;

    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:self.bounds.size format:format];
    UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
        CGContextRef context = rendererContext.CGContext;
        if (self.opaque) {
            CGSize size = self.bounds.size;
            size.width *= self.contentsScale;
            size.height *= self.contentsScale;
            CGContextSaveGState(context); {
                if (!self.backgroundColor || CGColorGetAlpha(self.backgroundColor) < 1) {
                    CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
                    CGContextAddRect(context, CGRectMake(0, 0, size.width, size.height));
                    CGContextFillPath(context);
                }
                if (self.backgroundColor) {
                    CGContextSetFillColorWithColor(context, self.backgroundColor);
                    CGContextAddRect(context, CGRectMake(0, 0, size.width, size.height));
                    CGContextFillPath(context);
                }
            } CGContextRestoreGState(context);
        }
        task.display(context, self.bounds.size, ^{return NO;});
    }];

    self.contents = (__bridge id)(image.CGImage);
CodeSlaveZhang

CodeSlaveZhang commented on Sep 26, 2023

@CodeSlaveZhang

如果不想像上面一样处理
可以在

  • (void)_displayAsync:(BOOL)async
    这个函数里面添加
    if (self.bounds.size.width<=0 || self.bounds.size.height<=0) {
    self.contents = nil;
    return;
    }
added 5 commits that reference this issue on Oct 19, 2023

bugfix: ibireme#984 UIGraphicsBeginImageContext() failed to allocate …

bugfix: ibireme#984 UIGraphicsBeginImageContext() failed to allocate …

bugfix: ibireme#984 UIGraphicsBeginImageContext() failed to allocate …

bugfix: ibireme#984 UIGraphicsBeginImageContext() failed to allocate …

bugfix: ibireme#984 UIGraphicsBeginImageContext() failed to allocate …

added a commit that references this issue on Oct 23, 2023
wanghaolyj

wanghaolyj commented on Oct 25, 2023

@wanghaolyj

如果不想像上面一样处理 可以在

  • (void)_displayAsync:(BOOL)async
    这个函数里面添加
    if (self.bounds.size.width<=0 || self.bounds.size.height<=0) {
    self.contents = nil;
    return;
    }

@implementation YYTextAsyncLayer(Hook)

  • (void)load {
    Method a = class_getInstanceMethod(self, @selector(display));
    Method b = class_getInstanceMethod(self, @selector(swizzing_display));
    method_exchangeImplementations(a, b);
    }
  • (void)swizzing_display{
    //通过变量名称获取类中的实例成员变量
    if (self.bounds.size.width<=0 || self.bounds.size.height<=0) {
    self.contents = nil;
    return;
    } else {
    [self swizzing_display];
    }
    }

@EnD

It's better to do this

ZackDT

ZackDT commented on Nov 2, 2023

@ZackDT

Swift的话,采用上面一样的hook方法,在appdelegate方法中调用 YYTextAsyncLayer.swizzleDisplay

`
import YYText
/// 避免iOS17的崩溃
extension YYTextAsyncLayer {

static let swizzleDisplay: Void = {
    let originalSelector = #selector(display)
    let swizzledSelector = #selector(swizzing_display)
    
    guard let originalMethod = class_getInstanceMethod(YYTextAsyncLayer.self, originalSelector),
          let swizzledMethod = class_getInstanceMethod(YYTextAsyncLayer.self, swizzledSelector) else {
        return
    }
    
    method_exchangeImplementations(originalMethod, swizzledMethod)
}()

@objc func swizzing_display() {
    if bounds.size.width <= 0 || bounds.size.height <= 0 {
        contents = nil
        return
    } else {
        swizzing_display()
    }
}

}
`

added a commit that references this issue on Nov 23, 2023

bugfix: ibireme#984 UIGraphicsBeginImageContext() failed

lizhi0123

lizhi0123 commented on Nov 29, 2023

@lizhi0123

I do not want to change code in pods. so I create two classe. PPYYLabel, PPYYTextAsyncLayer . user PPYYLabel replace YYLabel


import Foundation
import YYText

///PPYYLabel 代替YYLabel ios17崩溃修复 
class PPYYLabel: YYLabel{
    override class var layerClass: AnyClass {
        return PPYYTextAsyncLayer.self
    }
}



import Foundation
import YYText

/// ios17崩溃修复 
class PPYYTextAsyncLayer: YYTextAsyncLayer {
    override func display() {
        if self.bounds.size.width<=0 || self.bounds.size.height<=0 {
            self.contents = nil
            return
        } else {
            print("---- bounds.width = , ",self.bounds.size.width , " ,height = ",self.bounds.size.height)
            super.display()
        }
    }
}


zhoumingwu

zhoumingwu commented on Dec 1, 2023

@zhoumingwu

It seems like the master has retired from the scene for many years. It's unlikely that he will make a comeback again

NubiaYin

NubiaYin commented on Dec 20, 2023

@NubiaYin

这个API还能继续用,只不过当layer的width或height 为0时会触发断言,否则不会。
这个场景在使用AutoLayout时比较常见。

MonicaZhou

MonicaZhou commented on May 6, 2024

@MonicaZhou

如果不想像上面一样处理 可以在

* (void)_displayAsync:(BOOL)async
  这个函数里面添加
  if (self.bounds.size.width<=0 || self.bounds.size.height<=0) {
  self.contents = nil;
  return;
  }

最低支持iOS9的代码,得用这个~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @lizhi0123@wanghaolyj@MonicaZhou@CodeSlaveZhang@w1090485608

        Issue actions

          UIGraphicsBeginImageContext Deprecated · Issue #984 · ibireme/YYText