- 场景1 ----------- runtime 发送消息 -----------
- objc/msgSend 只有对象才能发送消息,因此以objc开头
- 导入 #import <objc/message.h> 或者直接导入 #import <objc/runtime.h>
- 注意 Xcode 6 之后代码检查 单独使用<objc/message.h>会报错
- builtSeting 修改 Enable Strict Checking of objc_msgSend Calls -> NO 才能调用 objc_msgSend `
我们创建一个对象Dog 自定义一个实例方法和类方法,并实现方法:
#import <Foundation/Foundation.h>
@interface Dog : NSObject
-(void)run;
+(void)eat;
@end
#import "Dog.h"
@implementation Dog
-(void)run
{
NSLog(@"一只狗正在奔跑");
}
+(void)eat
{
NSLog(@"一只狗正在吃。。。");
}
@end
然后我们在vc里面使用
// 创建对象 -> 调用方法
Dog *d = [[Dog alloc] init];
// 调用方法 -> 实例方法
[d run];
// 系统底层本质 -> 让对象发消息
objc_msgSend(d, @selector(run)); // 等同于 [d run];
// 调用方法 -> 类方法
[Dog eat];
objc_msgSend([Dog class], @selector(eat)); // 等同于 [Dog eat];
消息机制原理:
对象根据方法编号SEL去映射表查找对应方法的实现,即我们在调用实例方法的时候,其实是实例对象d,在发送消息,消息的实现,其实是SEL,根据方法编号,去映射表查找对应方法的实现.类方法本质是[Dog class],发什么消息.
- 场景2 ----------- runtime 交换方法 -----------
使用场景,系统自带方法功能不够用,给系统自带的方法扩展一些功能,并保存原有功能:- 实现方法 1 -> 继承系统的类, 重写方法.
- 实现方法 2 -> runtime 交换方法
案例:这里我们写一个UIImage的类目,来保证UIImage,不会被渲染,同时,如果图片为空,会打印提示.
#import <UIKit/UIKit.h>
@interface UIImage (Image)
// 创建一个类方法
// 传入 一个字符串 -> 返回 不被 渲染的原始图片
+ (id)ImageOriginalWithStrName:(NSString *)name;
@end
在.m进行实现, 使用method_exchangeImplementations(method1, method2)方法交换,详情看代码注释.
#import "UIImage+image.h"
#import <objc/runtime.h>
@implementation UIImage (image)
+(void)load
{
//获取方法
Method imageWithName = class_getClassMethod(self, @selector(imageOriginaWithStrName:));
Method imageName = class_getClassMethod(self, @selector(imageNamed:));
//交换方法
method_exchangeImplementations(imageWithName, imageName);
}
+(id)imageOriginaWithStrName:(NSString *)name
{
UIImage *image = [[self imageOriginaWithStrName:name] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
if (image == nil) {
NSLog(@"加载图片为空");
}
return image;
}
@end
在vc中使用 :
UIImage *image = [UIImage imageNamed:@"123"];