IOS 图片存放3种方式

IOS 图片存放3种方式

IOS小彩虹2021-07-12 11:46:2660A+A-

Image.xcassets

  • 创建 .xcassets,以 Image Set 形式管理图片,添加图片后会生成对应的 content.json 文件
  • 加入 @2x@3x 等倍图后,打包后以 Assets.car 的形式存在,
  • 使用 [UIImage imageNamed:@"xxx"] 方式读取图片,可以使用图片缓存 —— 相当于创建了一个 key-value的字典,key 为图片名,value 为图片对象。创建图片对象后,该对象被加入到 NSCache 中(解码后的 Image Buffer),直到收到内存警告的时候,才会释放不在使用的图片对象。 因此,对于需要在多处显示的图片,其对应的 UIImage 对象只会被创建一次(不考虑内存警告时的回收),减少内存消耗。

图片直接加入工程中作为Resource

  • 读取方式:创建图片 Resource 文件夹,直接将图片加入到工程中,使用如下方式读取图片
NSString *path = [NSBundle.mainBundle pathForResource:@"xxx" type:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
  • 特性:在 Resource 的图片管理方式中, 所有的图片创建都是通过读取文件数据得到的, 读取一次文件数据就会产生一次 NSData 以及产生一个 UIImage。 当图片创建好后销毁对应的 NSData,当 UIImage 的引用计数器变为 0 的时候自动销毁 UIImage,这样的话就可以保证图片不会长期地存在在内存中

  • 使用场景:由于这种方法的特性, 所以 Resource 的方法一般用在图片数据很大, 图片一般不需要多次使用的情况,比如说引导页背景(图片全屏)

  • 优势:图片不会长期保存在内存当中, 所以不会有很多的内存浪费。同时, 大图一般不会长期使用, 而且大图占用内存一般比小图多了好多倍, 所以在减少大图的内存占用中, Resource 做的非常好

使用Bundle文件

  • Bundle 即资源文件包,将许多图片,XIB,文本文件组织在一起,打包成一个 Bundle 文件,方便在其他项目中引用包内的资源。
  • Bundle 文件是静态的,不参与项目的编译Bundle 包中不能包含可执行的文件,它仅仅是作为资源,被解析成为特定的二进制数据。
  • 优势:Bundle 中文件不参与项目编译,不影响App包的大小(可用于App的瘦身); 使用 bundle 方式方便对文件进行管理,方便在其他项目中引用包内的资源。
  • 使用场景:较大的图片,或者使用频率较低的图片
  • 读取方式:使用 imageWithContentsOfFile 进行读取,如下方法1;也可以对 UIImage 进行扩展,如下方法2
  1. 使用 imageWithContentsOfFile 读取
/// BSKDefine.h

// bundle path
#define STBundle_Name @"SafeToolResource.bundle"
#define STBundle_Path [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:STBundle_Name]
#define STBundle [NSBundle bundleWithPath:STBundle_Path]
/// usage

#import "BSKDefine.h"
UIImageView * headerBgImgView = [[UIImageView alloc] init];
headerBgImgView.image = [UIImage imageWithContentsOfFile:[SecKill_BUNDLE pathForResource:@"xxxx" ofType:@"png"]];
  1. UIImage 进行扩展,创建 UIImage+BSKResources
/// UIImage+BSKResources.h

NS_ASSUME_NONNULL_BEGIN

@interface UIImage (BSKResources)

+ (UIImage *)bskImageNamed:(NSString *)imageName InBundleName:(NSString *)bundleName;

@end

NS_ASSUME_NONNULL_END
/// UIImage+BSKResources.m

#import "UIImage+BSKResources.h"

@implementation UIImage (BSKResources)

+ (UIImage *)bskImageNamed:(NSString *)imageName InBundleName:(NSString *)bundleName
{
    NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:bundleName];
    NSBundle *resourceBundle = [NSBundle bundleWithPath:resourcePath];
    return [UIImage imageNamed:imageName inBundle:resourceBundle compatibleWithTraitCollection:nil];
}
@end
/// usage

#import "UIImage+BSKResources.h"

UIImageView * headerBgImgView = [[UIImageView alloc] init];
headerBgImgView.image = [UIImage bskImageNamed:@"xxx" InBundleName:@"BSKResources.bundle"]];

Bundle 和 xcassets 区别

  • xcassets 里面的图片,只能通过 imageNamed 加载。Bundle 还可以通过 imageWithContentsOfFile 等方式加载
  • xcassets 里的 2x3x,会根据具体设备分发,不会同时包含(App Slicing),而 Bundle 会都包含
  • xcassets 内,可以对图片进行 Slicing,即裁剪和拉伸,Bundle 不支持
  • Bundle 内支持多语言,xcassets 不支持
  • 此外,使用 imageNamed 创建的 UIImage,会立即被加入到 NSCache 中(解码后的 Image Buffer),直到收到内存警告的时候,才会释放不在使用的 UIImage;而使用 imageWithContentsOfFile 创建的对象,每次都会重新申请内存,相同图片不会缓存。因此,建议常用的、较小的图,放在 xcassets 内管理,而大图、使用频率较低的图,应该放在 Bundle 内管理

图片资源文件大小计算

在日常开发中,会针对App包体积大小进行优化和瘦身。以往,常常以为本地开发工程中的资源文件大小就是最后安装包中的大小,将本地图片压缩一下就可以瘦身。

而根据 干货!京东商城iOS App瘦身实践 文章观点,很多图片在本地和安装包中的大小差异非常之大,往往相差几倍,甚至有几十倍的。通过调研知道 Apple 为了在优化 iPhone 设备读取 png 图片速度,将 png 转换成 CgBI 非标准的 png 格式

  • extra critical chunk (CgBI)
  • byteswapped (RGBA -> BGRA) pixel data, presumably for high-speed direct blitting to the framebuffer
  • zlib header, footer, and CRC removed from the IDAT chunk
  • premultiplied alpha (color' = color * alpha / 255)

苹果的优化对于大多数应用来说都是包大小的负优化,商城也不例外。所以简单的压缩(有损,无损)处理并不能达到很好的瘦身效果。而经过测试,以下文件会被负优化

  • 放在根目录下png格式的图片
  • 放在Asset Catalog中的png,jpg格式的图片,其中jpg会转成png

而放在根目录下的 jpg,bundle 中的 png 不会被优化,本地图片的大小,就是安装包中资源文件的大小。

其他

截取图片中间部分展示

业务开发中,遇到需要截取图片中间部分进行展示的需求,如上图所示。记录其实现方式如下

self.topBgImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,100,100)];
//展示图片中间部分
[_topBgImgView setContentScaleFactor:[[UIScreen mainScreen] scale]];
_topBgImgView.contentMode =  UIViewContentModeScaleAspectFill;
_topBgImgView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
_topBgImgView.clipsToBounds  = YES;

参考 IOS 关于UIImageView的显示——居中显示或者截取图片的中间部分显示 | CSDN 了解更多。

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们