【问题标题】:Intermittent crash using AVFoundation to create a UIView that contains a QR使用 AVFoundation 创建包含 QR 的 UIView 的间歇性崩溃
【发布时间】:2020-01-16 00:28:47
【问题描述】:

我在使用 AVFoundation 创建一个 UIView 的程序中遇到了一个非常间歇性的崩溃,该 UIView 包含来自传入字符串的二维码。它不会经常发生,但随着我的 TestFlight 用户使用该应用程序的时间而发生。

这是来自 Xcode 9 组织者的崩溃日志。

我创建了一个协议和扩展来处理 QRCode 的创建并将其放入 UIView。我的 UITableViewCell 符合 QRCodeImageProtocol

protocol QRCodeImageProtocol : class {
func generateQRCode(from string: String, forImageViewSize imageViewSize: CGSize) -> UIImage?

}

extension QRCodeImageProtocol {

func generateQRCode(from string: String, forImageViewSize imageViewSize: CGSize) -> UIImage? {
    let generatorKey = "CIQRCodeGenerator"
    let inputMessageKey = "inputMessage"
    let inputCorrectionLevelKey = "inputCorrectionLevel"
    let qrCodeCorrectionLevel: String = "M"

    if let data = string.data(using: .isoLatin1),
        let filter = CIFilter(name: generatorKey, withInputParameters: [inputMessageKey : data, inputCorrectionLevelKey : qrCodeCorrectionLevel]),
        let qrCodeImage = filter.outputImage {

        let x = imageViewSize.width / qrCodeImage.extent.size.width
        let y = imageViewSize.height / qrCodeImage.extent.size.height

        let transform = CGAffineTransform(scaleX: x, y: y)

        let output = qrCodeImage.transformed(by: transform)
        return UIImage(ciImage: output)
    } else {
        return nil
    }
}

然后在我的 UITableViewCell 中,我监视用于创建 QR 码的字符串并调用协议函数以在字符串值更改时返回图像,最后我将 UIImageView 的视图设置为该 QRCode 图像。

@IBOutlet weak var qrCodeImageView: UIImageView!

    var recordName: String? {
    didSet {
        if let qrString = recordName {
            qrCodeImageView.image = generateQRCode(from: qrString, forImageViewSize: qrCodeImageView.frame.size)
        }
    }
}

这在 99% 的情况下都有效,但是在运行应用程序一天左右后,崩溃日志报告器中没有任何崩溃返回给我 - 我遇到了崩溃,然后是另一个,然后是另一个间隔小时或一天,或者相隔几天。

谁能建议我可能做错了什么?这是 Xcode 9 Swift 4.x 非测试版。测试人员正在运行 iOS 11.2.6。

【问题讨论】:

    标签: ios swift avfoundation crash-reports core-image


    【解决方案1】:

    确保您没有调用任何从后台线程创建/设置视图的代码。是否有可能从非主线程调用didSet?我会将didSet 的内容包装在DispatchQueue.main.async { ... } 中以确认不是这种情况。

    【讨论】:

      【解决方案2】:

      我知道这已经很老了,但我想用我的经验来扩展 Dylan 的回应。在我的代码(目标 C)中,当 QR 码读取开始时,AVCaptureDevice videoPreviewLayer 被动态添加到 UIView。

       _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
      [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
      [_videoPreviewLayer setFrame:_imgScan.layer.bounds];
      [_imgScan.layer addSublayer:_videoPreviewLayer];    
      [_captureSession startRunning]; 
      

      这是在主线程上完成的。导致我的错误的原因是,当读取过程停止时,videoPreviewLayer 正在从另一个线程的超级层中删除。这导致了布局错误NSInternalInconsistencyException,“原因:'在从主线程访问布局引擎后,不得从后台线程对其进行修改。'”

      我终于发现[_videoPreviewLayer removeFromSuperlayer] 也应该在主线程上使用dispatch_async(dispatch_get_main_queue() 完成:

       -(void)stopReading{
           [_captureSession stopRunning];
           _captureSession = nil;
           dispatch_async(dispatch_get_main_queue(), ^{
           [self->_videoPreviewLayer removeFromSuperlayer];
                  });    
      

      (我希望我说得通。)

      【讨论】:

        猜你喜欢
        • 2013-06-14
        • 2012-12-31
        • 2015-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-15
        • 1970-01-01
        相关资源
        最近更新 更多