使用libwebp渲染WebP图片时遭遇EXC_BAD_ACCESS错误求助
在Swift中使用libwebp渲染WebP图片时解决EXC_BAD_ACCESS错误
我尝试在Swift中使用libwebp库在UIImageView中渲染WebP图片,但遇到了以下错误:
Thread 4: EXC_BAD_ACCESS (code=2, address=0x700008d57f38)
已确认libwebp库已正确链接,目标URL的WebP图片有效,以下是我实现的简化代码:
import UIKit import libwebp extension UIImageView { func renderWebPImage(from url: URL) { DispatchQueue.global().async { guard let webpData = try? Data(contentsOf: url) else { return } // Decode the WebP image data using libwebp guard let image = webpDecode(webpData) else { return } DispatchQueue.main.async { // Create a UIImage from the decoded data and assign it to the UIImageView self.image = UIImage(cgImage: image) } } } private func webpDecode(_ data: Data) -> CGImage? { // Decode the WebP image data using libwebp guard let webpDataPointer = data.withUnsafeBytes({ $0.baseAddress }), let webpDataLength = data.withUnsafeBytes({ $0.count }) as? Int else { return nil } // Create a WebPDecoderConfig object var config = WebPDecoderConfig() // Initialize the WebPDecoderConfig with default values WebPInitDecoderConfig(&config) // Decode the WebP image data and populate the WebPDecoderConfig object let result = withUnsafeMutablePointer(to: &config) { configPointer -> Int32 in return WebPDecode(webpDataPointer, webpDataLength, configPointer) } guard result == VP8_STATUS_OK, let image = config.output.u.RGBA.webpDecodedImage() else { return nil } return image } } extension WebPRGBABuffer { func webpDecodedImage() -> CGImage? { let colorSpace = CGColorSpaceCreateDeviceRGB() guard let context = CGContext( data: self.rgba, width: Int(self.width), height: Int(self.height), bitsPerComponent: 8, bytesPerRow: Int(self.stride), space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue ) else { return nil } guard let cgImage = context.makeImage() else { return nil } return cgImage } } // Usage: let imageView = UIImageView() let url = URL(string: "https://example.com/image.webp")! imageView.renderWebPImage(from: URL)
错误原因与修复方案
1. 内存泄漏与野指针问题
libwebp解码后会在config.output.u.RGBA.rgba分配堆内存,但你的代码未调用WebPFree释放该内存。当config变量超出作用域后,内存被回收,后续访问CGImage时会触发野指针错误。
修复:使用defer语句确保无论解码成功与否,都释放libwebp分配的内存;同时CGContext.makeImage()会复制数据,释放原内存不会影响生成的CGImage。
2. 错误的解码API调用
你使用的WebPDecode并非搭配WebPDecoderConfig的正确函数,应该使用WebPDecodeIntoConfig来填充传入的配置对象。
3. Data指针处理冗余
data.withUnsafeBytes的使用存在冗余,data.count本身就是Int类型,无需强制转换。
4. 使用代码中的低级错误
最后调用renderWebPImage时传入了类型URL而非实例url,会直接导致编译/运行错误。
修正后的完整代码
import UIKit import libwebp extension UIImageView { func renderWebPImage(from url: URL) { DispatchQueue.global().async { [weak self] in guard let self = self else { return } guard let webpData = try? Data(contentsOf: url) else { print("Failed to load WebP data from URL") return } guard let image = self.webpDecode(webpData) else { print("Failed to decode WebP image") return } DispatchQueue.main.async { self.image = UIImage(cgImage: image) } } } private func webpDecode(_ data: Data) -> CGImage? { let webpDataPointer = data.withUnsafeBytes { $0.baseAddress } let webpDataLength = data.count guard let pointer = webpDataPointer, webpDataLength > 0 else { return nil } var config = WebPDecoderConfig() WebPInitDecoderConfig(&config) // 使用正确的API填充解码配置 let result = WebPDecodeIntoConfig(pointer, webpDataLength, &config) guard result == VP8_STATUS_OK else { WebPFreeConfig(&config) return nil } // 确保解码完成后释放libwebp分配的内存 defer { WebPFree(config.output.u.RGBA.rgba) } guard let image = config.output.u.RGBA.webpDecodedImage() else { return nil } return image } } extension WebPRGBABuffer { func webpDecodedImage() -> CGImage? { let colorSpace = CGColorSpaceCreateDeviceRGB() guard let context = CGContext( data: self.rgba, width: Int(self.width), height: Int(self.height), bitsPerComponent: 8, bytesPerRow: Int(self.stride), space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue ) else { return nil } // makeImage()会复制上下文数据,后续释放原内存不影响CGImage guard let cgImage = context.makeImage() else { return nil } return cgImage } } // 修正后的调用代码 let imageView = UIImageView() guard let url = URL(string: "https://example.com/image.webp") else { fatalError("Invalid WebP image URL") } imageView.renderWebPImage(from: url)
额外注意点
- 添加
[weak self]避免UIImageView被提前释放时出现悬垂指针问题 - 补充错误日志打印,方便排查加载/解码失败的原因
- 生产环境中建议替换
try? Data(contentsOf: url)为带错误处理的网络请求,避免同步阻塞线程
内容的提问来源于stack exchange,提问作者NinjaDeveloper
相关产品推荐
相关产品推荐

