Tencent / QMUI_iOS

QMUI iOS——致力于提高项目 UI 开发效率的解决方案
http://qmuiteam.com/ios
Other
7.11k stars 1.39k forks source link

通过 Core Image 生成二维码转为 UIImage 对象赋值给 UIImageView 时报错 #607

Closed sunimp closed 5 years ago

sunimp commented 5 years ago

Bug 表现 问题的具体描述 通过 Core Image 生成二维码, 在转为 UIImage 对象去赋值给 UIImageView 时, 二维码图像无显示, 控制台打印方法 hook 的报错和调用栈信息, 具体如下:

截图 Xcode 控制台的错误信息和 Bug 现场的界面截图以及有问题的代码截图

方法 hook 抛出的错误:

OverrideImplementation_block_invoke_2:118 | QMUILogLevelWarn | UIImageView | displayLayer: 没有初始实现,<UIImageView: 0x7ff3e7e5ced0; frame = (20 100; 380 380); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x60000114b560>>

堆栈信息:

(
    0   我的App                         0x000000010a097816 __OverrideImplementation_block_invoke_2 + 214,
    1   我的App                         0x000000010a095a38 __25+[UIImageView(QMUI) load]_block_invoke_2.80 + 456,
    2   QuartzCore                          0x000000010dca9c21 -[CALayer display] + 180,
    3   QuartzCore                          0x000000010dcbc003 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 359,
    4   QuartzCore                          0x000000010dc2b3aa _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 328,
    5   QuartzCore                          0x000000010dc62584 _ZN2CA11Transaction6commitEv + 608,
    6   QuartzCore                          0x000000010dc62ede _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 76,
    7   CoreFoundation                      0x000000010b7320f7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23,
    8   CoreFoundation                      0x000000010b72c5be __CFRunLoopDoObservers + 430,
    9   CoreFoundation                      0x000000010b72cc31 __CFRunLoopRun + 1505,
    10  CoreFoundation                      0x000000010b72c302 CFRunLoopRunSpecific + 626,
    11  GraphicsServices                    0x000000011712c2fe GSEventRunModal + 65,
    12  UIKitCore                           0x0000000114620ba2 UIApplicationMain + 140,
    13  我的App                         0x0000000109ecfc00 main + 64,
    14  libdyld.dylib                       0x00000001116e3541 start + 1,
    15  ???                                 0x0000000000000005 0x0 + 5,
)

模拟器表现截图: image

上图表现的代码部分: image

如何重现

  1. 创建一个 UIImageView 并生成一个 CIImage 转换为 UIImage 赋值, 就会报错
  2. 代码

    self.qrcodeImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 100, 380, 380)];
    self.qrcodeImageView.backgroundColor = UIColorRed;
    [self.view addSubview:self.qrcodeImageView];
    NSData *stringData = [@"https://www.google.com/" dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:NO];
    
    CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    [filter setValue:stringData forKey:@"inputMessage"];
    [filter setValue:@"Q" forKey:@"inputCorrectionLevel"];
    
    CIImage *outImage = filter.outputImage;
    
    CGFloat scaleX = 300 / outImage.extent.size.width;
    CGFloat scaleY = 300 / outImage.extent.size.height;
    CIImage *transformedImage = [outImage imageByApplyingTransform:CGAffineTransformMakeScale(scaleX, scaleY)];
    
    self.qrcodeImageView.image = [UIImage imageWithCIImage:transformedImage];

预期的表现 正常情况下, 是可以正常生成并显示, 新建一个项目是可以正常生成并显示的, 下图为不引入 QMUI 或注释掉 UIImageView+QMUI 分类中的 + (void)load 方法时的表现: image

其他信息

sunimp commented 5 years ago

可以确定的是, 与 UIImageView+QMUI.h 分类有关, 我在注释了 + (void)load 之后是可以正常表现的, 我注意到在此分类中 QMUI hook 了 UIImageView 的部分方法:

其中错误是由 displayLayer: 方法抛出的, 似乎是 QMUI 把 Core Image 生成 CIImage 转化成的 UIImage 判定为了 qimgv_animatedImage ? 我目前还不是很清楚为什么会这样, 各位大佬有知道的可以提供一些信息或者思路吗? 感谢你们提供开源组件, 它为我节省了很多时间并且提供了很多惊喜, 鞠躬!

MoLice commented 5 years ago

已发布 3.2.1 修复该问题。

sunimp commented 5 years ago

非常感谢!

sunimp commented 5 years ago

另外, 如果把 CIImage 通过 CIContext 创建为 CGImageRef 然后再通过 CGContextDrawImage 绘制成 bitmap, 然后再生成 UIImage 就没问题了...... 我昨天是这么解决的😂