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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:20:54