BOYYANG/1/blog/compressed/王艺瑾 4K美女壁纸 3840x2560_彼岸图网-f058fd72b17fdff17204112aea1ed857

ios加载大量高分辨率图片是部分图片显示空白并且报错(CGBitmapContextInfoCreate: unable to allocate 530841600 bytes for bitmap data)

作者: boyyang
分类: Swift
发布: 2025-06-18 08:37:35
更新: 2025-06-18 08:37:35
浏览: 6

背景

       在开发ios应用的时候,我有个图片无限加载的场景。由于有很多图片都是高分辨率的图片。在开发阶段这些图片都能够正常加载。但是打包到真机测试的时候,有些图片就无法显示并且在xcode控制台中显示(CGBitmapContextInfoCreate: unable to allocate 530841600 bytes for bitmap data)在网上找了很多相关的解决方案。大多数都是说使用kingfisher,SDImage等等用来做图片缓存。但是使用后也会出现这个问题。而且这个问题还是偶发性的。并不是每次都出现,但是在图片加载越来越多的时候就会出现该问题。

问题分析

       根据报错信息感觉就是因为图片太大了导致无法渲染,但是如果单独渲染这张图片,它又能正常显示。由于图片已经进行过压缩了,所以也就无法在图片压缩上做处理了。

解决方案

       我通过使用Nuke图片缓存框架获取到图片数据后为图片生成缩略图,然后再渲染到页面,本来是根据页面图片的宽高来设置byPreparingThumbnail的ofSize的,但是渲染出来的图片清晰度有点低,所以参数都乘上2后图片也就清晰了。打包后再次测试也就没有显示空白,也没有报错了

       部分代码如下:

import SwiftUI
import Nuke

struct SDWebImage: View {
    @State var url: URL
    @State var thumbnailUrl: URL?
    @State var size: CGSize = .init(width: 200, height: 200)
    @State private var image: UIImage?
    
    
    func getImage() async throws  {
        let imageTask = ImagePipeline.shared.imageTask(with: url)
        for await _ in imageTask.progress {

        }
        
        let image = try await imageTask.image.byPreparingThumbnail(ofSize: CGSize(width: size.width * 2, height: size.height * 2))
        
        self.image = image
    }

    var body: some View {
        if (image != nil) {
            Image(uiImage: image)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: size.width, height: size.height)
                .clipShape(
                    RoundedRectangle(
                        cornerSize: CGSize(width: 10, height: 10),
                        style: .continuous
                    )
                )
        }else{
            Group {
                if #available(iOS 26.0, *) {
                    Color
                        .clear
                        .frame(width: size.width, height: size.height)
                        .clipShape(RoundedRectangle(cornerSize: CGSize(width: 10, height: 10), style: .continuous))
                        .glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 10.0))
                } else {
                    Color
                        .orange
                        .clipShape(RoundedRectangle(cornerSize: CGSize(width: 10, height: 10), style: .continuous))
                        .frame(width: size.width, height: size.height)
                }
            }
            .onAppear{
                Task {
                    try await getImage()
                }
            }
        }
    }
}

总结

       之前为了解决这个问题使用了各种方法,由于是偶发性的,在使用了SDWebImageSwiftUI,NukeUi,KingFisher等等图片缓存框架后偶尔还是会出现。找了很久都没有找到合适的解决方案。后来想到使用缩略图,通过图片缓存下载后生成缩略图后再渲染,也就省略了所有图片重新上传缩略图了,同时也可以调节缩略图的清晰度。

#swift
#swift ui
#ios