XZ_iOS之Runtime使用运行时交换方法

交叉(交换)方法,在无法修改系统或者第三方框架的方式时,利用交叉方法,先执行自己的方法,再执行系统或第三方的方法

在AFNNetworking框架中也使用了这种方式,AFURLSessionManager类中

XZ_iOS之Runtime使用运行时交换方法

NSURLSession中AFN交换了resume/suspend方法! 当网络请求开始或者挂起的时候,能够发送通知!
XZ_iOS之Runtime使用运行时交换方法

使用运行时交叉方法,实现调整图像尺寸 代码实现如下:
XZViewController.m
 // 交叉方法:实现调整图像尺寸
    UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    iv.center = self.view.center;
   
    [self.view addSubview:iv];
   
    // 设置图像 - bundle 中的 jpg 在加载的时候,需要制定扩展名
    iv.image = [UIImage imageNamed:@"商品图_03.jpg"];
//  相当于调用 iv setImage:<#(UIImage * _Nullable)#>

UIImageView+XZHack.h
#import <UIKit/UIKit.h>

@interface UIImageView (XZHack)

// 当在其他位置调用 ’setImage‘ 方法时,'自动'调用 xz_setImage: 方法
- (void)xz_setImage:(UIImage *)image;

@end

UIImageView+XZHack.m
#import "UIImageView+XZHack.h"
#import <objc/runtime.h>

@implementation UIImageView (XZHack)

+ (void)load {
    // 1.获取 UIImageView 类的 实例方法  'setImage:'
    Method originalMethod = class_getClassMethod([self class], @selector(setImage:));
    // 2.获取 UIImageView 类的 实例方法  'xz_setImage:',本身定义在分类中
    Method swizzledMethod = class_getClassMethod([self class], @selector(xz_setImage:));
    // 3.交换方法 setImage xz_setImage,交换完成之后
    // 1> 调用 setImage 相当于调用了 xz_setImage
    // 2> 调用 xz_setImage 相当于调用了 setImage
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

// 当在其他位置调用 ’setImage‘ 方法时,'自动'调用 xz_setImage: 方法
- (void)xz_setImage:(UIImage *)image {
    NSLog(@"%s",__FUNCTION__);
   
    // 1.根据 imageView的大小,重新调整 image 的大小
    // 使用 ‘CG’ 重新生成一张和目标尺寸相同的图片
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0);
   
    // 绘制图像
    [image drawInRect:self.bounds];
   
    // 取得结果
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
   
    // 关闭上下文
    UIGraphicsEndImageContext();
   
    // 调用系统默认的 setImage 方法
    [self xz_setImage:result];
}

@end