第二篇:runtime消息机制笔录

此篇博客概览:

1.消息发送:利用消息发送机制可以更改消息的接受者,以及更改方 法,另外方法的调用其实就是给某个接收者发送消息

2.动态解析:去实现系统的方法解析出没有方法实现的类添加类方法或者实例方法 

3.消息转发:去实现系统方法把调用者转发给另外调用者的实现 ,或者不转发给其它的调用者就注册方法,并重写 forwardInvocation方法,

4.添加类和成员变量:利用runtime生成一个类,并给该类添加成员变量或者方法,然后注册该类

5.数据归档和解档:利用runtime便利该类的所有成员变量,利用kvc归档或者解档 

6.方法交换:为该类添加一个类别,在该类中load方法里交换方法的实现                                                                                  

一.消息发送机制:

//类一:

@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];

     //对象方法调用 [p run] 等同于 objc_msgSend(p, @selector(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, "v@:");

//    }

    //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:"v@:"];

    }

    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, "v@:");

      //注意添加成员变量必须在注册前添加

    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];

}

 

学习截图如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值