第二篇:runtime消息机制笔录
一.消息发送机制:
//类一:
@interface Persion : NSObject
- (void)walk;
- (void)run;
@end
@implementation Persion
- (void)walk{
NSLog(@"%s", __func__);
}
- (void)run{
NSLog(@"%s", __func__);
}
//类二:
@interface Dog : NSObject
- (void)walk;
- (void)run;
@end
@implementation Dog
- (void)walk{
NSLog(@"%s", __func__);
}
- (void)run{
NSLog(@"%s", __func__);
}
//具体实现如下
#import <objc/runtime.h>
#import "Persion.h"
#import "Dog.h"
void run(){
NSLog(@"%s", __func__);
}
// 接收者:target 方法编号:selector
int main(int argc, const char * argv[]) {
@autoreleasepool {
Persion* p = [Persion new];
Dog* d = [Dog new];
//1.更换接收者
// object_setClass(p, [Dog class]);
// [p walk];
//2.更换方法编号的指向
Method m1 = class_getInstanceMethod([Dog class], @selector(walk));
// method_setImplementation(m1, (IMP)run);
// [d walk];
//3.0同时更换接收者和方法编号
Method m2 = class_getInstanceMethod([Persion class], @selector(run));
IMP imp = method_getImplementation(m2);
method_setImplementation(m1, imp);
[d walk];
}
return 0;
}
//利用runtime调用方法
#import <objc/message.h>
#import "Persion.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Persion* p = [Persion new];
//对象方法调用 [p run] 等同于 objc_msgSend(p, @selector(run))
[p run];
objc_msgSend(p, @selector(run));
//类方法调用 [p walk] 等同于 objc_msgSend(p, @selector(walk))
// [Persion walk];
// objc_msgSend(objc_getClass("Persion"), @selector(walk));
}
return 0;
}
二.动态方法解析
//对象方法的动态解析
#import "Persion.h"
#import <objc/message.h>
@implementation Persion
//void run(){
//}
- (void)run{
NSLog(@"%s", __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
//c方法的动态解析
// if (sel == @selector(run)) {
// return class_addMethod(self, sel, (IMP)run, "[email protected]:");
// }
//oc方法的解析
if (sel == @selector(run)) {
Method m1 = class_getInstanceMethod(self, @selector(run));
IMP runImp = method_getImplementation(m1);
const char* types = method_getTypeEncoding(m1);
return class_addMethod(self, sel, runImp, types);
}
return [super resolveInstanceMethod:sel];
}
@end
#import <Foundation/Foundation.h>
#import "Persion.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[[Persion new] run];
}
return 0;
}
//类方法的动态解析
#import "Persion.h"
#import <objc/runtime.h>
@implementation Persion
+ (void)run{
NSLog(@"%s", __func__);
}
//实例对象->类对象->元类对象->根元类对象
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(walk)) {
//实例方法的元类就是当前类本身
Method runMethod = class_getInstanceMethod(object_getClass(self), @selector(run));
IMP runIMP = method_getImplementation(runMethod);
const char* types = method_getTypeEncoding(runMethod);
NSLog(@"%s", types);
return class_addMethod(object_getClass(self), sel, runIMP, types);
}
return [super resolveClassMethod:sel];
}
//+ (BOOL)resolveClassMethod:(SEL)sel {
// if (sel == @selector(walk)) {
// Method runMethod = class_getClassMethod(self, @selector(run));
// IMP runIMP = method_getImplementation(runMethod);
// const char* types = method_getTypeEncoding(runMethod);
// NSLog(@"%s", types);
// return class_addMethod(object_getClass(self), sel, runIMP, types);
// }
// return [super resolveClassMethod:sel];
//}
//注意:下面的为错误写法(objc_getClass和object_getClass的区别)
//+ (BOOL)resolveClassMethod:(SEL)sel{
// if (sel == @selector(walk)) {
// Method m1 = class_getClassMethod(self, @selector(run));
// IMP runImp = method_getImplementation(m1);
// const char* types = method_getTypeEncoding(m1);
// return class_addMethod(objc_getClass(self), sel, runImp, types);
// }
// return [super resolveClassMethod:sel];
//}
@end
三.消息转发机制:
#import "Persion.h"
#import "Dog.h"
@implementation Persion
//+ (void)walk{
// NSLog(@"%s", __func__);
//}
- (void)run{
NSLog(@"%s", __func__);
}
//消息转发
//如果没有对应的方法可以更换接收者去执行对应的方法
- (id)forwardingTargetForSelector:(SEL)aSelector{
//把Persion的walk方法转给Dog去执行 (注意walk是对象方法)
// if (aSelector == @selector(walk)) {
// return [Dog new];
// }
return [super forwardingTargetForSelector:aSelector];
}
//方法名注册
//没有对应的方法,没有更换接收者,则可以注册方法,但是必须执行forwardInvocation方法,否则报错
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(walk)) {
return [NSMethodSignature signatureWithObjCTypes:"[email protected]:"];
}
return [super methodSignatureForSelector:aSelector];
}
//此处方法执行了便不会报错,可以为一个空的方法,可以不用再转发
- (void)forwardInvocation:(NSInvocation *)anInvocation{
// [anInvocation invokeWithTarget:[Dog new]];
anInvocation.selector = @selector(run);
[anInvocation invoke];
}
#import <Foundation/Foundation.h>
#import "Persion.h"
//打印runtime运行执行顺序机制
// cd /private/tmp/
//ls
//open msgSend1430 (查看运行明细)
extern void instrumentObjcMessageSends(BOOL);
int main(int argc, const char * argv[]) {
@autoreleasepool {
instrumentObjcMessageSends(YES);
[[Persion new] walk];
instrumentObjcMessageSends(NO);
}
return 0;
}
四.数据归档,解档
//类一:
@interface Persion : NSObject
@property(strong, nonatomic)NSString* name;
@property(strong, nonatomic)NSString* nack;
@property(assign, nonatomic)int age;
@end
#import "Persion.h"
#import <objc/runtime.h>
@implementation Persion
- (void)encodeWithCoder:(NSCoder *)coder{
unsigned int count = 0;
Ivar* ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar var = ivars[i];
const char* name = ivar_getName(var);
NSString* key = [NSString stringWithUTF8String:name];
id value = [self valueForKey:key];
[coder encodeObject:value forKey:key];
}
free(ivars);
}
- (instancetype)initWithCoder:(NSCoder *)coder{
if (self == [super init]) {
unsigned int count = 0;
Ivar* iVars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = iVars[i];
const char* name = ivar_getName(ivar);
NSString* key = [NSString stringWithUTF8String:name];
id value = [coder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
free(iVars);
}
return self;
}
@end
//入口方法
- (void)archiverTest{
Persion* p = [Persion new];
p.name = @"jhh";
p.age = 18;
p.nack = @"jzs";
NSString* path = [NSString stringWithFormat:@"%@/archiver.plist", NSHomeDirectory()];
NSLog(@"-----%@", NSHomeDirectory());
//归档
[NSKeyedArchiver archiveRootObject:p toFile:path];
//解档
Persion* p1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@-----%d====%@", p.name, p.age, p.nack);
}
五.添加类和成员变量
- (void)addClassTest{
Class Cat = objc_allocateClassPair([NSObject class], "Cat", 0);
NSString* name = @"name";
class_addIvar(Cat, name.UTF8String, sizeof(id), log2(sizeof(id)), @encode(id));
class_addMethod(Cat, @selector(hunting), (IMP)hunting, "[email protected]:");
//注意添加成员变量必须在注册前添加
objc_registerClassPair(Cat);
id cat = [[Cat alloc] init];
[cat setValue:@"Tom" forKey:name];
NSLog(@"%@", [cat valueForKey:name]);
[cat performSelector:@selector(hunting)];
}
void hunting(id self, SEL _cmd){
NSLog(@"maomao---%s", __func__);
}
六.方法交换(俗称黑魔法)
#import "UIViewController+Hook.h"
#import <objc/runtime.h>
@implementation UIViewController (Hook)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method m1 = class_getInstanceMethod(self, @selector(viewWillAppear:));
Method m2 = class_getInstanceMethod(self, @selector(jhh_viewWillAppear:));
method_exchangeImplementations(m1, m2);
});
}
- (void)jhh_viewWillAppear:(BOOL)animated{
NSLog(@"%s", __func__);
}
@end
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
}
学习截图如下: