Objectiv-C 方法调用偷龙转凤(Method Swizzling)

伦敦iOS小牛 2014-05-13 05:31:45

更多技术文章请关注我的微博: http://weibo.com/u/2822867275

------------------------------------------

在修改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:] 这个方法替换掉。


PS:
在iOS7中, 如果你的 UIBarButtonItem 是以 initWithCumstomView: 建立的,会出现移位的情况,这时可以用 Method Swizzling 来解决,详情请关注小牛的的下一篇文章。




#import <UIKit/UIKit.h>

@interface UIImage (Common)
+(UIImage*)myImageNamed: (NSString*)imageName;
@end


#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 image;
}

@end
...全文
266 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
微信公众号 2014-05-22
  • 打赏
  • 举报
回复
写的太长了楼主,直接一句话概括就是:类目中声明的新方法优先级高,会覆盖原类中的同名方法。
勤奋的执着 2014-05-21
  • 打赏
  • 举报
回复
引用 4 楼 wen2034 的回复:
要理智替换啊,小的资源图片还是用imageNamed ,大图才imageWithContentsOfFile
同意啊,不过楼主的文章也不错,mark下
wen2034 2014-05-20
  • 打赏
  • 举报
回复
要理智替换啊,小的资源图片还是用imageNamed ,大图才imageWithContentsOfFile
伦敦iOS小牛 2014-05-20
  • 打赏
  • 举报
回复
正因为imageNamed 有缓存, 所以在使用很多高清图片时内存很快就阳痿了。。。
yan_daoqiu 2014-05-20
  • 打赏
  • 举报
回复
并不是imageNamed不能用的,这个函数有缓存作用,imageWithContentsOfFile 没有缓存。
_Finder丶Tiwk 2014-05-19
  • 打赏
  • 举报
回复
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:file ofType:ext]] 这个方法性能是强,但是没有缓存,而[UIImage imageNamed:__imageName]有。

29,028

社区成员

发帖
与我相关
我的任务
社区描述
主要讨论与iOS相关的软件和技术
社区管理员
  • iOS
  • 大熊猫侯佩
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧