使用Kingfisher加载API返回SVG图片报错,求解决方案
修复Kingfisher加载SVG图片时的崩溃问题
问题背景
API返回SVG和PNG格式的图片,使用Kingfisher无法正常下载SVG图片,自定义SVGImgProcessor处理后运行崩溃,错误提示无法分配CGContext,原因是图片尺寸为{0,0}。
现有代码
SVGImgProcessor
import UIKit import Kingfisher import SVGKit public struct SVGImgProcessor: ImageProcessor { public var identifier: String = "com.appidentifier.webpprocessor" public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? { switch item { case .image(let image): print("already an image") return image case .data(let data): let imsvg = SVGKImage(data: data) return imsvg?.uiImage } } }
CoinItemCell
final class CoinItemCell: UITableViewCell { @IBOutlet weak var itemLabel: UILabel! @IBOutlet weak var coinImageView: UIImageView! override func awakeFromNib() { super.awakeFromNib() // Initialization code } func prepareCell(with item: CoinItemVM) { itemLabel.text = item.name let processor = SVGImgProcessor() coinImageView.kf.setImage(with: item.coinImage, options: [.processor(processor)]) } }
错误信息
*** Assertion failure in +[SVGLength pixelsPerInchForCurrentDevice], SVGLength.m:238 *** Assertion failure in void _UIGraphicsBeginImageContextWithOptions(CGSize, BOOL, CGFloat, BOOL)(), UIGraphics.m:410 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UIGraphicsBeginImageContext() failed to allocate CGBitampContext: size={0, 0}, scale=3.000000, bitmapInfo=0x2002. Use UIGraphicsImageRenderer to avoid this assert.' *** First throw call stack: ( 0 CoreFoundation 0x0000000180491128 __exceptionPreprocess + 172 1 libobjc.A.dylib 0x000000018008412c objc_exception_throw + 56 2 Foundation 0x0000000180d11770 -[NSMutableDictionary(NSMutableDictionary) classForCoder] + 0 3 UIKitCore 0x0000000184e9af20 _UIGraphicsBeginImageContextWithOptions + 564 4 CoinList 0x00000001009ba370 +[SVGKExporterUIImage exportAsUIImage:antiAliased:curveFlatnessFactor:interpolationQuality:] + 388 5 CoinList 0x00000001009cfbe0 -[SVGKImage UIImage] + 56 6 CoinList 0x000000010084ce78 $s8CoinList15SVGImgProcessorV7process4item7optionsSo7UIImageCSg10Kingfisher16ImageProcessItemO_AJ0I17ParsedOptionsInfoVtF + 492 7 CoinList 0x000000010084d230 $s8CoinList15SVGImgProcessorV10Kingfisher05ImageD0AadEP7process4item7optionsSo7UIImageCSgAD0F11ProcessItemO_AD0E17ParsedOptionsInfoVtFTW + 20 8 CoinList 0x0000000100915b48 $s10Kingfisher18ImageDataProcessorC9doProcess33_6119A2C527FFA834F85B326B80E79A62LLyyF + 1164 9 CoinList 0x00000001009156ac $s10Kingfisher18ImageDataProcessorC7processyyFyycACcfu_yycfu0_ + 36 10 CoinList 0x0000000100956e40 $s10Kingfisher13CallbackQueueO7executeyyyycFyyYbcfU1_ + 64 11 CoinList 0x000000010086351c $sIegh_IeyBh_TR + 48 12 libdispatch.dylib 0x0000000101d180f0 _dispatch_call_block_and_release + 24 13 libdispatch.dylib 0x0000000101d1993c _dispatch_client_callout + 16 14 libdispatch.dylib 0x0000000101d21bd8 _dispatch_lane_serial_drain + 916 15 libdispatch.dylib 0x0000000101d2291c _dispatch_lane_invoke + 420 16 libdispatch.dylib 0x0000000101d2f2f8 _dispatch_root_queue_drain_deferred_wlh + 324 17 libdispatch.dylib 0x0000000101d2e754 _dispatch_workloop_worker_thread + 488 18 libsystem_pthread.dylib 0x0000000101db3924 _pthread_wqthread + 284 19 libsystem_pthread.dylib 0x0000000101db26e4 start_wqthread + 8 ) libc++abi: terminating due to uncaught exception of type NSException
修复方案
崩溃核心原因是解析后的SVGKImage尺寸为{0,0},导致转换UIImage时无法创建合法的CGContext。需要修改处理器,强制设置有效渲染尺寸:
修改后的SVGImgProcessor
import UIKit import Kingfisher import SVGKit public struct SVGImgProcessor: ImageProcessor { public var identifier: String = "com.appidentifier.svgprocessor" private let targetSize: CGSize // 初始化时传入目标渲染尺寸(比如ImageView的实际大小) public init(targetSize: CGSize) { self.targetSize = targetSize } public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? { switch item { case .image(let image): return image case .data(let data): guard let svgImage = SVGKImage(data: data) else { return nil } // 处理SVG尺寸为0的异常情况,强制使用目标尺寸 var renderSize = svgImage.size let scale = UIScreen.main.scale if renderSize.width <= 0 || renderSize.height <= 0 { renderSize = CGSize(width: targetSize.width * scale, height: targetSize.height * scale) } // 按尺寸渲染SVG svgImage.size = renderSize return svgImage.uiImage } } }
修改Cell调用逻辑
func prepareCell(with item: CoinItemVM) { itemLabel.text = item.name // 传入ImageView的实际尺寸作为SVG渲染目标尺寸 let processor = SVGImgProcessor(targetSize: coinImageView.bounds.size) coinImageView.kf.setImage(with: item.coinImage, options: [.processor(processor)]) }
额外优化建议
可以加入异常捕获,避免因SVG解析失败导致崩溃:
public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? { switch item { case .image(let image): return image case .data(let data): do { guard let svgImage = SVGKImage(data: data) else { return nil } var renderSize = svgImage.size let scale = UIScreen.main.scale if renderSize.width <= 0 || renderSize.height <= 0 { renderSize = CGSize(width: targetSize.width * scale, height: targetSize.height * scale) } svgImage.size = renderSize return svgImage.uiImage } catch { print("SVG解析失败: \(error.localizedDescription)") return nil } } }
内容的提问来源于stack exchange,提问作者Ufuk Köşker
相关产品推荐
相关产品推荐

