ios中修改imageactionnamename和修改imageactionnamewithcontentsoffile的区别

大图用 imageWithContentsOfFile 小图用imageNamed - 博客频道 - CSDN.NET
分类:ios 开发
在修改xcode比较大的项目时,通常会遇到一种很蛋疼的情况:&项目中很多地方调用一个方法,但是这个方法的功能不太理想,于是你想修改这个方法,最后发现这个方法来源于一个Lib,&没有代码,只有&定义在&.h&文件,泥马没有代码怎么修改阿?
小牛哥在做&Westfield&Leasing&这个项目时也遇到类似的操蛋经历,这个app用到很多tmd大图片,一般正常人都用&[UIImage&imageNamed:&]&这个方法,但是在调试中发现,泥马这个方法会不断占用cash的内存,导致程序很快就阳痿(内存不够)!&而&[UIImage&imageWithContentsOfFile:]&就不会。
这样我们单独写一个方法好了,&像[UIImage&xpImageNamed:]&这样的category!&里面调用imageWithContentsOfFile:&就好了?
听起来可行,但两个问题:
1.&在一个大项目里,人员流动也频繁,有新人进来你得不断的告诉他/她:别用imageNamed:啦,会阳痿的。。。&要是新人是个小清纯,你好意思不?
2.&项目里原来可能就有几百个地方用imageNamed:,&如果用一个新的函数代替,将会有几百个地方要修改,这个不是高效率的方法。&而且当你commit&代码时,别的程序员看到这么多地方被修改,得拿出看AV的认真态度,多累阿。。。
所以最好的方法是在整个项目中替换掉imageNamed:这个方法,&当其他人用这个方法时,系统其实会调用另一个方法!
请看下面代码!
以下方法称为&Method&Swizzling,&当你引用下面的头文件时,在整个项目中[UIImage&imageNamed:&]&&这个方法会被&[UIImage&myImageNamed:]&这个方法替换掉。&
在iOS7中,&如果你的&UIBarButtonItem&是以&initWithCumstomView:&建立的,会出现移位的情况,这时可以用&Method&Swizzling&来解决,详情请关注小牛的的下一篇文章。
#import&&UIKit/UIKit.h&
@interface&UIImage&(Common)
+(UIImage*)myImageNamed:&(NSString*)imageN
#import&&UIImage+Common.h&
#import&&objc/runtime.h&
#import&&objc/message.h&
@implementation&UIImage&(Common)
//&load&在初始化类时调用,每个类都有一个load&方法,
//&类的初始化先于对象
+(void)load
&&&&//以下方法就告诉系统用后面的方法替换前面的
&&&&method_exchangeImplementations(class_getClassMethod(self,&@selector(imageNamed:)),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&class_getClassMethod(self,&@selector(myImageNamed:)));
+(UIImage*)myImageNamed:&(NSString*)imageName
&&&&//&图片要支持jpg&和png&
&&&&NSString&*path&=&[[NSBundle&mainBundle]&pathForResource:imageName&ofType:@&png&];
&&&&if&(path&==&nil)
&&&&&&&&path&=&[[NSBundle&mainBundle]&pathForResource:imageName&ofType:@&jpg&];
&&&&//&这里image&在回收后不会占用cash&内存
&&&&UIImage&*image&=&[UIImage&imageWithContentsOfFile:path];
&&&&return&
排名:第14660名
(74)(32)(6)(4)(5)(0)(2)(5)(2)(1)(1)使用OC加载图片的两种方式及其区别 - 简书
下载简书移动应用
写了11095字,被1人关注,获得了2个喜欢
使用OC加载图片的两种方式及其区别
在iOS中加载图片的方式有多种,通过OC的方式主要有imageName:和imageWithContentsOfFile:两种。这两种方式如何使用,以及他们之间的区别是什么呢?下面通过两个小示例来详细讲解。
一、imageNamed:和imageWithContentsOfFile:的使用
1、imageNamed:
新建一个工程,将准备好的图片拖入项目中Assets.xcassets文件夹中,具体步骤如下图所示:
来到ViewController.m文件,在viewDidLoad方法中加载图片:
UIImageView *imageView = [[UIImageView alloc] init];
// 创建imageView对象
imageView.frame = CGRectMake(0, 0, 265, 395);
// 设置imageView的尺寸
imageView.center = self.view.
// 让图片在中间位置显示
imageView.image = [UIImage imageNamed:@"0009"];
// 加载图片
[self.view addSubview:imageView];
// 显示图片
显示结果如下:
2、imageContentsOfFile:
与上面一样,新建一个工程,然后再将图片资源拖入到项目中。与上面不一样的是,这次图片资源不是拖入Assets.xcassets文件夹中,而是拖入到Supporting Files文件夹中,原因后面再做解释。详细步骤如下图所示:
需要注意的是,在拖入图片的过程中Xcode会弹出一个"Choose options for adding these files"的提示框,一般按照上图所示选择默认勾选项就可以了(其中Create groups表示在项目中创建虚拟文件夹,而Create folder references表示创建实际文件夹),如果不勾选的话,会出问题。图片资源拖入完成以后效果如下图所示:
通过imageWithContentOfFile:的方式加载图片资源的代码如下:
UIImageView *imageView = [[UIImageView alloc] init];
// 创建imageView对象
imageView.frame = CGRectMake(0, 0, 265, 395);
// 设置imageView的尺寸
imageView.center = self.view.
// 让图片在中间位置显示
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"0010" ofType:@"jpg"];
// 获取图片资源所在路径
imageView.image = [UIImage imageWithContentsOfFile:imagePath];
// 加载图片
[self.view addSubview:imageView];
// 显示图片
运行结果如下图所示:
二、imageNamed:和imageWithContentsOfFile:的区别
1、打包方式上的不同
项目完成以后,所有的图片资源会被一起打包成ipa文件发布到AppStore,拖入Assets.xcassets文件夹中的图片最后会被打包成一个Assets.car文件,我们不能根据路径读取图片。而拖入Supporting Files文件夹中的图片可以根据路径读取。另外,从某种程度上讲,拖入Assets.xcassets文件夹中的图片因为被打包成了Assets.car文件,可以得到一定程度上的保护,以防止盗图(之所以说是一定程度,是因为我们依然可以通过其他手段解压相关图片)。而拖入Supporting Files文件夹中的图片则直接暴露在外面。可以通过下面一系列图片来验证我们的一些结论(验证方法见:):
点击"Bundle"——"Application",然后找到当前项目:
右击当前项目,选择"显示包内容",可以看到我们拖入到Assets.xcassets文件夹中名称为0009.jpg的图片没有了,其实他被打包到Assets.car文件夹里面去了。而拖入到Supporting Files文件夹中名称为0010.jpg的图片可以直接查看:
我们可以借助iOS images Extractor插件来验证名称为0009.jpg的图片是否被打包到Assets.car文件中:
2、出于内存和程序性能方面的考虑
除了像上面提到的打包方式上的差别之外,还有另外一个重要的区别,就是从内存和程序性能方面的考虑。为了说明这个问题,我们需要借助另外一个小程序来作进一步的说明。
新建一个工程,分两步来讨论通过不同的方式加载图片所表现出来的程序性能的问题。
通过imageNamed:方法来加载图片。首先将准备好的素材拖入到项目中的Assets.xcassets文件夹当中,然后通过imageNamed:方法来加载:
加载图片的代码如下:
// 抽取加载图片重复的代码
- (NSArray *)loadImagesWithImagePrefixName:(NSString *)prefixName count:(int)count
NSMutableArray&UIImage *& *images = [NSMutableArray array];
// 创建一个可变数组,用于装载图片
for (int i = 0; i & i++) {
NSString *imageName = [NSString stringWithFormat:@"%@_%d", prefixName, i + 1];
// 获取图片的名称
UIImage *image = [UIImage imageNamed:imageName];
// 加载图片
[images addObject:image];
// 将图片添加到可变数组中
// 返回数组
运行程序来查看内存使用情况:
我们可以看到站立情况下,内存始终是29M左右。点击小招以后内存上升到35.8M,点击大招以后,内存上升到57.2M。这主要是因为每点击一次不同的招数,系统就会加载更多的图片,因此造成内存使用量增加。
重点在于点击停止按钮以后。点击停止按钮所执行的代码如下:
// 游戏结束
- (IBAction)gameOver {
self.standImages =
self.smallImages =
self.bigImages =
self.imageView.animationImages =
理论上讲,我们点击停止按钮以后,保存在数组中的图片资源被清空,内存使用量应该下降,但事实上却并没有:
产生上述问题的主要原因是,通过imageNamed:方法加载的图片,其图片在使用完成后,并不会立即被释放掉,具体释放时间由系统决定。因此,这种加载方法,适用于图片小、数量少,且经常使用的图片处理场合。
通过imageWithContentsOfFile:方法来加载图片。和上面一样,将准备好的素材拖入到项目中,不过这次不是拖入到Assets.xcassets文件夹,而是直接拖入到Supporting Files文件夹中,具体情况如下图所示:
修改加载图片的代码:
// 抽取加载图片重复的代码
- (NSArray *)loadImagesWithImagePrefixName:(NSString *)prefixName count:(int)count
NSMutableArray&UIImage *& *images = [NSMutableArray array];
// 创建一个可变数组,用于装载图片
for (int i = 0; i & i++) {
NSString *imageName = [NSString stringWithFormat:@"%@_%d", prefixName, i + 1];
// 获取图片的名称
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];
// 获取图片在资源包中的路径
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
// 加载图片
[images addObject:image];
// 将图片添加到可变数组中
// 返回数组
修改完成以后运行程序,点击小招、大招,程序运行时占用内存的情况与通过imageNamed:方式加载图片运行时的情况是一样的。但是,当我们点击停止按钮以后,发现内存使用量又降为29.4M左右了:
这个主要是因为,通过imageWithContentsOfFile:方法加载的图片可以快速的手动释放。
通过这个示例,我们基本上可以总结出imageNamed:和imageWithContentsOfFile:这两个方法的使用场合:
1、imageNamed:方法适用于经常使用,并且图片小、数量少的场合,方便快速加载;2、imageWithContentsOfFile:方法适用于图片比较大,并且图片数量非常多的场合,此时需要考虑程序的性能。
完整的代码:
工作交流:
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:评论 - 509IOS学习(4)
imageNamed
1) [UIImage imageNamed:ImageName]
2) 在application bundle的顶层文件夹寻找相应名字的图象,找到后系统会把图像Cache到内存(对于同一个图像系统只会把它Cache到内存一次),如果再次要用同一图像,图像将从内部缓存而不是从资源中加载,这对于图像的重复利用是非常有优势的。例如:你需要在一个TableView里重复加载同样一个图标,那么用imageNamed加载图像,系统会把那个图标Cache到内存,在Table里每次利用那个图像的时候,只会把图片指针指向同一块内存。这种情况使用imageNamed加载图像就会变得非常有效。
3) 但是,如果图像比较大,或者图像比较多,用这种方式会消耗很大的内存,而且释放图像的内存是一件相对来说比较麻烦的事情。例如:如果利用imageNamed的方式加载图像到一个动态数组NSMutableArray,然后将将数组赋予一个UIView的对象的animationImages进行逐帧动画,那么这将会很有可能造成内存泄露。又如在使用Interface Builder建立界面时,如果直接拖动UIImageView
并设置image的图片名称,InterfaceBuilder 正是通过UIImage 类的imageName方法加载图片,图片被缓存,导致内存使用较大,且无法释放,即使release掉 UIImageView也无济于事。
4) 创建出的内存不可分页。
imageWithContentsOfFile
1).& NSString *path = [[NSBundlemainBundle] pathForResource:@”icon” ofType:@”png”];
&&&&& myImage = [UIImage imageWithContentsOfFile:path];
2).不为图像提供缓存,调用的时候去加载,推荐使用。
3).创建出的内存可分页
imageWithData
1). NSString *filePath = [[NSBundlemainBundle] pathForResource:fileName ofType:extension];
&&& NSData *image = [NSData dataWithContentsOfFile:filePath];
&&& [UIImage imageWithData:image]
2).不为图像提供缓存,从二进制数据创建,利用NSData方式加载时,图像会被系统以数据方式加载到程序。当你不需要重用该图像,或者你需要将图像以数据方式存储到数据库,又或者你要通过网络下载一个很大的图像时,请尽量使用imageWithData的方式加载图像。
3).创建出的内存不可分页
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:4719次
排名:千里之外
原创:11篇
(1)(2)(1)(1)(1)(3)(9)(1)iOS-UIImage imageWithContentsOfFile
和 imageName 对比
iOS-UIImage imageWithContentsOfFile
和 imageName 对比
UI设计-iOS
1.imageWithContentsOfFile
NSString *imagePath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] resourcePath],@"icon.png"];
UIImage *imageI = [UIImage imageWithContentsOfFile:imagePath];
imageWithContentsOfFile的方式,在使用完成之后系统会释放,不会缓存下来,所以也就没有这样的问题。一般也不会把所有的图片都会缓存。有些图片在应用中只使用一两次的,就可以用这样的方式,比如新手引导界面的图片等等,就适合这样的方式。没有明显的界限。
2.imageName
UIImage *image = [UIImage imageNamed:@"icon"];
imageName的方式会在使用的时候系统会cache,程序员是无法处理cache,这是由系统自动处理的,对于重复加载的图像,速度会提升很多,这样反而用户体验好。所以如果某张图片需要在应用中使用多次,或者重复引用,使用imageName的方式会更好,
所以,在app中一些经常会使用的,需要重复加载的,使用imageName会提升用户体验!
Apple的官方文档:
imageNamed: 这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。因此imageNamed的优点是当加载时会缓存图片。所以当图片会频繁的使用时,那么用imageNamed的方法会比较好。例如:你需要在 一个TableView里的TableViewCell里都加载同样一个图标,那么用imageNamed加载图像效率很高。系统会把那个图标Cache到内存,在TableViewCell里每次利用那个图 像的时候,只会把图片指针指向同一块内存。正是因此使用imageNamed会缓存图片,即将图片的数据放在内存中,iOS的内存非常珍贵并且在内存消耗过大时,会强制释放内存,即会遇到memory warnings。而在iOS系统里面释放图像的内存是一件比较麻烦的事情,有可能会造成内存泄漏。例如:当一 个UIView对象的animationImages是一个装有UIImage对象动态数组NSMutableArray,并进行逐帧动画。当使用imageNamed的方式加载图像到一个动态数组NSMutableArray,这将会很有可能造成内存泄露。原因很显然的。
imageWithContentsOfFile:仅加载图片,图像数据不会缓存。因此对于较大的图片以及使用情况较少时,那就可以用该方法,降低内存消耗。
一、加载图片问题
UIImage image = [UIImage imageNamed:imageFileName];
这种图片加载方式带有图片缓存的功能,使用这种方式加载图片后,图片会自动加入系统缓存中,并不会立即释放到内存。一些资源使程序中经常使用的图片资源,
使用这种方式会加快程序的运行减少IO操作,但对于项目中只用到一次的图片,如果采用这种方案加载,会增导致程序的内存使用增加。
以下为官方对此方法的解释说明:
imageNamed:
Returns the image object associated with the specified filename.
(UIImage )imageNamed:( NSString ) name
Parameters
The name of the file. If this is the first time the image is being loaded, the method looks for an image with the specified name in the application’s main bundle.
Return Value
The image object for the specified file, or nil if the method could not find the specified image.
Discussion
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already
in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
二、非缓存的加载方式
+ (UIImage )imageWithContentsOfFile:(NSString )path
(UIImage )imageWithData:(NSData )data
三、何时使用imageNamed方法
1、采用imageNamed方法的图片加载情况
图片资源反复使用到,如按钮背景图片的蓝色背景,这些图片要经常用到,而且占用内存少
2、不应该采用的情况:
(1)图片一般只使用一次,如一些用户的照片资源
(2)图片资源较大,加载到内存后,比较耗费内存资源
我的热门文章
即使是一小步也想与你分享

我要回帖

更多关于 修改imageactionname 的文章

 

随机推荐