You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升SwiftUI中二维码(QR Code)生成的速度?

优化Swift二维码生成速度的实用技巧

针对你遇到的二维码生成耗时问题,结合你的代码场景,以下是几个可落地的优化方向:

1. 复用CIContext,避免重复初始化

CIContext的创建是高开销操作,你当前每次调用generateQRCode都新建一个实例,这会浪费大量资源。将其改为静态常量复用:

struct HandOverView: View {
    let store: StoreOf<LogicReducer>
    @State var qrCode: Image?
    // 静态复用CIContext
    private static let ciContext = CIContext()
    
    // ... 其他代码
    
    func generateQRCode(from string: String) -> Image? {
        let filter = CIFilter.qrCodeGenerator()
        filter.message = Data(string.utf8)

        if let outputImage = filter.outputImage {
            // 使用预创建的ciContext
            if let cgImage = Self.ciContext.createCGImage(outputImage, from: outputImage.extent) {
                return Image(uiImage: UIImage(cgImage: cgImage))
            }
        }
        return nil
    }
}

2. 异步生成二维码,避免阻塞主线程

当前你在onAppear的主线程中同步执行生成逻辑,会导致UI卡顿。将生成操作移到后台队列,完成后再回到主线程更新UI:

.onAppear {
    UIScreen.main.brightness = 1.0
    
    DispatchQueue.global(qos: .userInitiated).async {
        do {
            let result = try StateSnapshot.createStateSnapshot(state: store.state)
            let generatedQRCode = generateQRCode(from: result)
            
            DispatchQueue.main.async {
                qrCode = generatedQRCode
            }
        } catch {
            print("Catch: \(error)")
        }
    }
}

3. 调整QR Code纠错级别(权衡速度与容错率)

默认的QR Code纠错级别是M(中等),如果你的使用场景对二维码容错率要求不高(比如仅近距离扫描、无污损风险),可以将纠错级别调低到L(低),生成速度会有所提升:

func generateQRCode(from string: String) -> Image? {
    let filter = CIFilter.qrCodeGenerator()
    filter.message = Data(string.utf8)
    // 设置低纠错级别
    filter.correctionLevel = "L"

    if let outputImage = filter.outputImage {
        if let cgImage = Self.ciContext.createCGImage(outputImage, from: outputImage.extent) {
            return Image(uiImage: UIImage(cgImage: cgImage))
        }
    }
    return nil
}

4. 压缩字符串内容(进一步减少数据量)

虽然你提到无法将字符数降到500以下,但可以尝试对字符串进行压缩(比如Gzip),减少二维码需要承载的数据量,从而加快生成速度:

// 新增字符串压缩扩展
extension String {
    func gzipCompressed() -> Data? {
        guard let data = self.data(using: .utf8) else { return nil }
        return try? data.gzipped()
    }
    
    // 对应的解压方法(扫描端需要实现解压逻辑)
    static func gzipDecompressed(from data: Data) -> String? {
        guard let decompressedData = try? data.gunzipped() else { return nil }
        return String(data: decompressedData, encoding: .utf8)
    }
}

// 生成二维码时使用压缩后的数据
func generateQRCode(from string: String) -> Image? {
    let filter = CIFilter.qrCodeGenerator()
    // 使用压缩后的数据
    guard let compressedData = string.gzipCompressed() else { return nil }
    filter.message = compressedData

    if let outputImage = filter.outputImage {
        if let cgImage = Self.ciContext.createCGImage(outputImage, from: outputImage.extent) {
            return Image(uiImage: UIImage(cgImage: cgImage))
        }
    }
    return nil
}

注意:这种方式需要扫描端配合实现对应的解压逻辑,确保能正确解析二维码内容。

5. 预缩放CIImage,减少后续UI渲染压力

CIQRCodeGenerator生成的原始CIImage尺寸很小,后续通过resizable()缩放可能增加UI层的开销。可以先将CIImage放大到目标尺寸(比如350x350)再转换为CGImage:

func generateQRCode(from string: String) -> Image? {
    let filter = CIFilter.qrCodeGenerator()
    filter.message = Data(string.utf8)
    filter.correctionLevel = "L"

    guard let outputImage = filter.outputImage else { return nil }
    
    // 计算缩放比例,将原始CIImage放大到目标尺寸
    let targetSize = CGSize(width: 350, height: 350)
    let scale = min(targetSize.width / outputImage.extent.width, targetSize.height / outputImage.extent.height)
    let scaledImage = outputImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
    
    if let cgImage = Self.ciContext.createCGImage(scaledImage, from: scaledImage.extent) {
        return Image(uiImage: UIImage(cgImage: cgImage))
    }
    return nil
}

内容的提问来源于stack exchange,提问作者mkdavor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:10:12