前言: 本章節(jié)是對(duì)上一章節(jié)的延伸,上一章對(duì)runtime的運(yùn)行機(jī)制沒做過多的解釋软啼,其一:我也是在學(xué)習(xí)了解過程中榛瓮,說白了也就是小白航背,只能寫一些我知道我理解的東西喉悴,其二:網(wǎng)上各個(gè)論壇以及網(wǎng)站都有一些大牛們的非常好的文章可以供大家參考閱讀。
交叉方法:
再次啰嗦一下他的作用和使用目的玖媚,它主要是用來替換系統(tǒng)的方法箕肃,當(dāng)然不是完全替換,底層的東西最好不要輕易修改今魔,那這里的交換對(duì)于大部分人來說就是在調(diào)用系統(tǒng)方法之前插入自己的方法勺像,然后再通過自己的方法調(diào)用原來系統(tǒng)的方法,以便達(dá)到自己的目的错森。
下面是通過交叉方法替換UIImageVIew的setIamge:方法做一些事情吟宦,具體是什么事情呢
大家在使用UIimageView的時(shí)候有些時(shí)候不得已需要設(shè)置ImageView的Frame然而在在得到set圖片的時(shí)候,圖片的大小和imageview的大小并不是一樣大的涩维,這就會(huì)產(chǎn)生拉伸殃姓,消耗性能,特別是在TableView快速滾動(dòng)的時(shí)候瓦阐,影響性能蜗侈,這個(gè)事例就是利用runtime機(jī)制來優(yōu)化ImageView
擴(kuò)展:加載頭像后 點(diǎn)擊——模擬器——點(diǎn)擊Debug——ColorMilasignedimages——> 頭像上面如果覆蓋了一層黃色的 說明圖像有所拉伸
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor =[UIColor redColor];
UIImageView * imageview =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
imageview.center = self.view.center;
imageview.image =[UIImage imageNamed:@"icon-120.png"];
[self.view addSubview:imageview];
// 目標(biāo) 在設(shè)置頭像的時(shí)候 攔截系統(tǒng)方法對(duì)頭像做一些事情
//例 AFN 中在AFNURLSessionManger類中 有一個(gè)af_resume,af_suspend 的方法中使用了內(nèi)聯(lián)函數(shù)交換了resume睡蟋,suspend 目的是為了替換系統(tǒng)的方法在之前 發(fā)一個(gè)通知監(jiān)聽網(wǎng)絡(luò)狀態(tài)(發(fā)起踏幻,和掛起監(jiān)聽)} ```
import <UIKit/UIKit.h>
@interface UIImageView (XW_SetFrame)
-(void)xw_setimage:(UIImage *)image;
@end```
#import "UIImageView+XW_SetFrame.h"
#import <objc/runtime.h>
/*
AFN 中AFNURLSessionManager中 static inline void af_swizzleSelector 可找到
Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
*/
@implementation UIImageView (XW_SetFrame)
// 當(dāng)系統(tǒng)加載運(yùn)行時(shí)的時(shí)候會(huì)調(diào)用的方法 在這里做交換方法
+(void)load
{
// 獲取 UIimageview 類的實(shí)力方法:setImage
Method originalMethod = class_getInstanceMethod([self class], @selector(setImage:));
//獲取 UIimageview 類的實(shí)力方法:xw_setimage
Method swizzledMethod = class_getInstanceMethod([self class], @selector(xw_setimage:));
// 交換
method_exchangeImplementations(originalMethod, swizzledMethod);
}
// 當(dāng)系統(tǒng)在調(diào)用Imageview的setimage的時(shí)候自動(dòng)調(diào)用我們的xw_setimage
-(void)xw_setimage:(UIImage *)image
{
NSLog(@"%s",__FUNCTION__);
// 根據(jù)imageview的大小生成一張和imageview大小相同的圖片
/*
self.bounds.size :繪制大小
yes:不touming
0:使用屏幕分辨率 自動(dòng)適配
*/
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0);
// 繪制
[image drawInRect:self.bounds];
// 取得結(jié)果
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
//關(guān)閉上下文
UIGraphicsEndImageContext();
// 交換后 調(diào)用setimage 相當(dāng)于調(diào)用xw_setimage
//調(diào)用xw_setimage相當(dāng)于調(diào)用setimage
[self xw_setimage:result];//也就是說這句是調(diào)用系統(tǒng)的setimage
}
@end```
![7EC02E4E-AD18-417C-B7FA-D788CD139F7F.png](http://upload-images.jianshu.io/upload_images/1460277-41cbcd9f8eb1bf0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
但是在后來發(fā)現(xiàn)使用交叉方法直接替換底層的setimge:會(huì)帶來一系列問題,主要原因是這種替換將會(huì)導(dǎo)致所有的UIimageView以及繼承UIimageView的類都會(huì)發(fā)生剪切薄湿,這就導(dǎo)致一些沒有設(shè)置Frame的也發(fā)生重繪叫倍,然而這地方繪制所取的區(qū)域是self.bounds,self.bounds 因?yàn)闆]有設(shè)置又為0,就會(huì)產(chǎn)生圖片不能顯示豺瘤,我在這地方加上判斷,如果判斷self.bounds設(shè)置過了听诸,才執(zhí)行剪切坐求,沒有設(shè)置就不進(jìn)行剪切,解決問題如下:
-(void)xw_setimage:(UIImage *)image
{
NSLog(@"%s",FUNCTION);
// 根據(jù)imageview的大小生成一張和imageview大小相同的圖片
/*
self.bounds.size :繪制大小
yes:不touming
0:使用屏幕分辨率 自動(dòng)適配
*/
if (self.bounds.size.width==0||self.bounds.size.height==0) {
[self xw_setimage:image];//也就是說這句是調(diào)用系統(tǒng)的setimage
}
else
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0);
// 繪制
[image drawInRect:self.bounds];
// 取得結(jié)果
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
//關(guān)閉上下文
UIGraphicsEndImageContext();
if (self.bounds.size.width==0||self.bounds.size.height==0) {
[self xw_setimage:image];
}
else
{
// 交換后 調(diào)用setimage 相當(dāng)于調(diào)用xw_setimage
//調(diào)用xw_setimage相當(dāng)于調(diào)用setimage
[self xw_setimage:result];//也就是說這句是調(diào)用系統(tǒng)的setimage
}
}
}```
然而問題并不止,尼瑪各個(gè)各個(gè)框架的Gif圖不能播放晌梨,也就意味著這個(gè)優(yōu)化模式不能用了桥嗤,交叉方法是這樣的使的,要想優(yōu)化只能繼承UIimageView 重寫setimage:方法在里面這個(gè)方法里面做圖片重繪仔蝌,保證獨(dú)立性
#import "XWImageView.h"
@implementation XWImageView
-(void)setImage:(UIImage *)image
{
NSLog(@"%s",__FUNCTION__);
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0);
// 繪制
[image drawInRect:self.bounds];
// 取得結(jié)果
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
//關(guān)閉上下文
UIGraphicsEndImageContext();
[super setImage:result];
}
@end```
同時(shí)也在尋求解決辦法泛领,歡迎大家提意見
#下一章待續(xù) 通過交叉方法實(shí)現(xiàn)右滑pop到上一個(gè)控制器