RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。
RunTime是一套比较底层的纯C语言API,属于1个C语言库,包含了很多底层的C语言API。
在我们平时编写的OC代码中,程序运行过程时,其实最终都是转成了runtime的C语言代码。
XCode7使用Runtime:
objc_msgSend()报错Too many arguments to function call ,expected 0,have3
解决方案: 关闭msg检查机制
一、发送消息
本质:
方法调用的本质,就是让对象发送消息。
方法:
objc_msgSend(id self
,SEL op, ...
)
Flower.h文件中
#import <Foundation/Foundation.h>
@interface Flower : NSObject
- (void)showName;
- (void)showOtherName:(NSString *)otherName;
+ (void)showPrice;
+ (void)showOtherPrice:(NSString *)otherPrice;
@end
Flower.m文件中
#import "Flower.h"
@implementation Flower
- (void)showName{
NSLog(@"LuisX");
}
- (void)showOtherName:(NSString *)otherName{
NSLog(@"%@", otherName);
}
+ (void)showPrice{
NSLog(@"100");
}
+ (void)showOtherPrice:(NSString *)otherPrice{
NSLog(@"%@", otherPrice);
}
@end
RuntimeViewController.m文件中(消息机制应用):
#pragma //////////消息机制//////////
#import "RuntimeViewController.h"
#import "Flower.h"
#import <objc/message.h> //必须导入
@interface RuntimeViewController ()
@end
@implementation RuntimeViewController
- (void)viewDidLoad {
[super viewDidLoad];
Flower *flower = [Flower new];
//////////调用实例方法//////////
[flower showName];
[flower showOtherName:@"FX"];
//本质(使用RunTime):对象发送消息
objc_msgSend(flower, @selector(showName));
objc_msgSend(flower, @selector(showOtherName:), @"FX");
//输出: LuisX
//输出: FX
//输出: LuisX
//输出: FX
//////////调用类方法//////////
[Flower showPrice];
[Flower showOtherPrice:@"200"];
//本质(使用RunTime):类发送消息
objc_msgSend([Flower class], @selector(showPrice));
objc_msgSend([Flower class], @selector(showOtherPrice:), @"200");
//输出: 100
//输出: 200
//输出: 100
//输出: 200
}
@end
二、方法交换
场景:
系统自带的方法功能不够,保持原有的功能给系统自带的方法扩展一些功能。
方法:
class_getClassMethod(__unsafe_unretained Class cls
,SEL name
)
method_exchangeImplementations(Method m1
,Method m2
)
说明:
Ivar : 成员变量 如果要是动态创建/修改/查看属性,可以使用Ivar。
Method : 成员方法 如果要是动态创建/修改/查看方法,可以使用Method。
拓展阅读:
RunTime Method
RuntimeViewController.m文件中(方法交换应用):
#pragma //////////方法交换//////////
#import "RuntimeViewController.h"
#import <objc/message.h> //必须导入
@interface RuntimeViewController ()
@end
@implementation RuntimeViewController
- (void)viewDidLoad {
[super viewDidLoad];
//////////调用imageNamed方法//////////
UIImage *image = [UIImage imageNamed:@"1.jpg"];
//输出: 图片为空
}
@end
@implementation UIImage (FXImage)
/**
* 加载分类到内存时调用
*
* 1.获取imageWithName方法地址
* 2.获取imageWithName方法地址
* 3.交换方法地址,相当于交换实现方式
*
*/
+ (void)load{
Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));
Method imageName = class_getClassMethod(self, @selector(imageNamed:));
method_exchangeImplementations(imageWithName, imageName);
}
/**
* 自定义imageWithName方法
*
* 1.既能加载图片,又能打印
* 2.此时调用imageWithName相当于调用imageName(二者已经交换)
*
* 注意:不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super.
*/
+ (instancetype)imageWithName:(NSString *)name{
UIImage *image = [self imageWithName:name];
if (image == nil) {
NSLog(@"图片为空");
}
return image;
}
@end
未完待续...