iOS 加载图片

iOS加载图片经历磁盘读取、数据解压缩(最耗内存)和渲染三个阶段。避免内存占用关键是缩减图片尺寸、异步解码、延迟解码和缓存管理,特别是大图应使用ImageIO下采样或分片加载。常用技术包括SDWebImage库的自动处理、图片下采样及长列表内存清理。
一、 iOS图片加载过程
iOS图片从加载到显示主要包括以下三个步骤:
加载(Load):通过 UIImage(named:) 或 UIImage(contentsOfFile:) 将磁盘上的图片文件(PNG, JPG等)读取到内存中,此时以数据块形式存在。
解码(Decode):这是最耗费内存的步骤。UIImage 将压缩的格式(如 JPG)解码为未压缩的位图格式(Bitmap)。位图内存占用大小计算公式为:

渲染(Render):Core Animation 管道将位图绘制到屏幕上。
二、 如何避免内存占用(普通图片)
优先使用 imageWithContentsOfFile::imageNamed: 具有系统缓存,适用于小图标,但加载大图会导致内存不释放。用该方法加载大图可在对象释放时即时释放内存。
阿里云开发者社区
阿里云开发者社区
压缩格式选择:优先使用PNG,尽量减少位图的像素总量。
SDWebImage 自动处理:使用SDWebImage进行异步加载和解码,其默认机制能很好地处理缓存和清理。

三、 特别处理:加载大图/高清图(防 Crash)
如果直接将几千像素的大图加载为 UIImage 再赋值给 UIImageView,通常会导致内存警告甚至崩溃(OOM)。
下采样(Downsampling/Downscaling):在解码前调整图片大小。这是优化大图最高效的方法,利用 ImageIO 框架读取图片尺寸而不将其全部加载到内存。
swift
// 示例:ImageIO 下采样
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let options: [NSString: Any] = [
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceThumbnailMaxPixelSize: max(width, height), // 目标尺寸
kCGImageSourceCreateThumbnailWithTransform: true
]
let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource!, 0, options as CFDictionary)

按需分片(Tiled Rendering):对于极大尺寸的地图或图集,使用 CATiledLayer 将图片切分成小块,仅加载当前屏幕显示的区域。
使用 drawInRect:先创建低分辨率缩略图绘制在 context 中显示。
长列表性能优化:在 UITableView 或 UICollectionView 滚动时,清除离开屏幕的 UIImageView 的 image 对象。
延迟解码(Lazy Decoding):在子线程强制解压缩图片(将image赋值给 CALayer)后再返回主线程显示,避免在主线程进行耗时的解码操作造成卡顿。

总结:小图用 imageNamed,大图用 imageWithContentsOfFile 配合 ImageIO 下采样,是解决iOS图片内存问题的不二法门。

Kingfisher 在 iOS 中实现圆角的核心逻辑是对原始图片进行像素级变换(Image Processor),而不是简单的视图层裁剪。
以下是它的核心原理:

  1. 核心类:RoundCornerImageProcessor
    当你使用 .processor(RoundCornerImageProcessor(cornerRadius: 20)) 时,Kingfisher 会执行以下步骤:
    开启位图上下文:在后台线程创建一个与原图大小一致的透明画布(CGContext)。
    绘制裁切路径:利用 UIBezierPath(roundedRect:...) 创建一个圆角矩形的路径。
    裁剪并渲染:将该路径设为裁剪区域(Clip),然后将原始图片绘制到画布中。
    生成新图:从上下文中导出处理后的 UIImage。
  2. 为什么不用 layer.cornerRadius?
    虽然 view.layer.cornerRadius 配合 masksToBounds 也能实现圆角,但 Kingfisher 选择通过 Processor 处理图片主要有两个原因:
    性能优化:layer 离屏渲染(Off-screen Rendering)在列表(如 TableView)滚动时会消耗大量 GPU 资源,导致卡顿。Kingfisher 在后台线程处理好图片像素,交给 GPU 时就是一个普通的矩形纹理,渲染效率极高。
    缓存机制:处理后的圆角图片会生成一个唯一的 cacheKey 并存入磁盘。下次加载时直接读取圆角图,无需再次计算。
  3. 处理后的结果
    最终,ImageView 接收到的是一张四个角已经是透明像素的新图片。
    需要注意的是:如果你的 contentMode 是 .scaleAspectFill,建议同时设置 Processor 的 targetSize,否则可能会出现圆角被拉伸或显示不全的情况。