iOS

iOS 图片处理的小 Tips

Posted by Puqin Chen on 2018-08-08

UIImage 的本地保存

保存 UIImage 有三种方式:

  1. 直接使用 NSKeyedArchiver,把 UIImage 序列化保存
  2. UIImagePNGRepresentation() 把图片转为 PNG 保存
  3. UIImageJPEGRepresentation() 把图片压缩成 JPEG 保存。

其中,方法一也是调用了 UIImagePNGRepresentation 进行序列化,用它保存图片的消耗是最大的。苹果对 JPEG 有硬编码和硬解码,保存成 JPEG 会大大缩减编码解码时间,也能减小文件体积。所以如果图片不包含透明像素时,UIImageJPEGRepresentation(0.9) 是最佳的图片保存方式,其次是 UIImagePNGRepresentation()

UIImage 的 缓存

通过 imageNamed 创建 UIImage 时,系统实际上只是在 Bundle 内查找到文件名,将其放到 UIImage 里返回。当显示在屏幕上时,内部的解码方法才会被调用,并且会将解码的结构保存在一个全局缓存里,并且会长期存在(除非收到内存警告)。也就是说imageNamed:会有图片缓存的功能,当下次访问图片的时候速度会更快。
用这种方式加载图片,图片的内存管理并不受程序员控制。

如果把image对象设置为nil,如果是其它对象,那么没有强指针指向一个对象,这个对象就会销毁;但是即使image = nil,它会指向的图片资源也不会销毁。

使用 imageWithData 能不能避免缓存?

答案是不能,通过数据创建 UIImage 时,UIImage 底层是调用 ImageIO 的 CGImageSourceCreateWithData() 方法。该方法有个参数叫 ShouldCache,在 64 位的设备上,这个参数是默认开启的。这个图片也是同样在第一次显示到屏幕时才会被解码,随后解码数据被缓存到 CGImage 内部。与 imageNamed 创建的图片不同,如果这个图片被释放掉,其内部的解码数据也会被立刻释放。

避免缓存的方法

  1. 手动调用 CGImageSourceCreateWithData() 创建图片,并关掉 ShouldCacheShouldCacheImmediately 。但是这种方式会导致每次图片显示到屏幕时,解码方法都会被调用,造成很大的 CPU 占用。
  2. 把图片用 CGContextDrawImage() 绘制到画布上,然后把画布的数据取出来当作图片。

几种方式加载图片

  • 第一种就是上面说的 imageNamed: 方法加载图片,因为有缓存功能,所以再次访问速度更快。具体可以看上面。
  • 通过 imageWithContentsOfFile: 方式加载图片:
    • 使用这个方法加载图片,当指向图片对象的指针销毁或指向其它对象,这个图片对象没有其它强指针指向,这个图片对象会销毁,不会一直在内存中停留。
    • 因为没有缓存,所以如果相同的图片多次加载,那么也会有多个图片对象来占用内存,而不是用缓存的图片。
    • 使用这个方法,需要file的全路径(之前用NSString, NSArray之类的加载文件也是一样的,比如stringWithContentsOfFile:,看到file就知道是需要传入全路径。)
    1
    2
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

注意如果图片在Images.xcassets中,是不能使用第二种方法的。所以说想要自己进行图片的内存管理,那么要将图片资源直接拖入工程,而不是放在Images.xcassets中。

PNG 与 JPEG 的区别

png是一种使用无损压缩的图片格式,而大家熟知的另外一种图片格式——jpeg则是采用有损压缩的方式。
用通俗易懂的方式来讲,当原图片数据被编码成png格式后,是可以完全还原成原本的图片数据的,而编码成jpeg则会损耗一部分图片数据,这是因为两者的编码方式和定位不同。jpeg着重于人眼的观感,保留更多的亮度信息,去掉一些不影响观感的色度信息,因此是有损耗的压缩。png则保留原始所有的颜色信息,并且支持透明/alpha通道,然后采用无损压缩进行编码。因此对于jpeg来说,通常适合颜色更丰富、可以在人眼识别不了的情况下尽可能去掉冗余颜色数据的图片,比如照片之类的图片;而png适合需要保留原始图片信息、需要支持透明度的图片。