蜜蜂浅谈Runtime Part2(菜鸟级别)

这一篇,我们了解一下runtime的交换/增加/跟踪方法

我们知道通过runtime可以获取的一个类的属性列表,其实还可以获取到这个类的协议和方法列表

#pragma mark - 获取方法列表(即使是没执行的方法也能获取)
    unsigned int count;
    Method *methodList = class_copyMethodList([self class], &count);
    for (unsigned int i=0; i<count; i++) {
        Method method = methodList[i];
        NSLog(@"ViewController 的方法有:%@", NSStringFromSelector(method_getName(method)));
    }
    
#pragma mark - 获取协议列表
    // * 这里我们写上tableview的协议
    __unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
    for (unsigned int i; i<count; i++) {
        Protocol *myProtocal = protocolList[i];
        const char *protocolName = protocol_getName(myProtocal);
        NSLog(@"ViewController 的协议有%@", [NSString stringWithUTF8String:protocolName]);
    }

接下来,我们先看一个比较简单的,动态增加方法

#pragma mark - 动态增加方法
- (void)add_method
{
    /**
     (IMP)guessAnswer 意思是guessAnswer的地址指针,所以增加的方法需要用runtime函数写;
     "v@:" 意思是,v代表无返回值void,如果是i则代表int;@代表 id sel; : 代表 SEL _cmd;
     “v@:@@” 意思是,两个参数的没有返回值。
     自己定义一个方法,我这里是myNewMethod,因为runtime里没有这个方法,则创建这个方法
     [self class]可以替换为其他的类
     */
    class_addMethod([self class], @selector(myNewMethod), (IMP)myNewMethod, "v@:");
    if ([self respondsToSelector:@selector(myNewMethod)]) {
        
        [self performSelector:@selector(myNewMethod)];
        
    } else{
        NSLog(@"Sorry,I don't know");
    }
}

// 这里是增加的方法
void myNewMethod(id self,SEL _cmd){
    NSLog(@"I am from GuangZhou");
}

其次是交换方法和跟踪方法,我们需要在+(void)load方法里声明,viewcontroller都会优先走load这个方法

这里我在BeeChangeMethodController里定义了一个类方法(beeChange_method),然后我们自己在viewcontroler写了一个(view_method)来交换他

+ (void)load
{
    // **************************** 动态交换两个方法的实现 ***************************************
    
    BeeChangeMethodViewController *beeChangeVC = [[BeeChangeMethodViewController alloc]init];
    Class PersionClass = object_getClass([beeChangeVC class]);
    Class toolClass = object_getClass([self class]);
    
    //源方法的SEL和Method   注意不要把selector里面的方法名写错
    SEL oriSEL = @selector(beeChange_method);
    Method oriMethod = class_getInstanceMethod(PersionClass, oriSEL);
    
    //交换方法的SEL和Method
    SEL cusSEL = @selector(view_method);
    Method cusMethod = class_getInstanceMethod(toolClass, cusSEL);
    
    //先尝试給源方法添加实现,这里是为了避免源方法没有实现的情况
    BOOL addSucc = class_addMethod(PersionClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
    if (addSucc) {
        // 添加成功:将源方法的实现替换到交换方法的实现
        class_replaceMethod(toolClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        
    }else {
        //添加失败:说明源方法已经有实现,直接将两个方法的实现交换即
        method_exchangeImplementations(oriMethod, cusMethod);
    }
    
    // *******************************************************************
    
    // ************* 跟踪记录APP中按钮的点击次数和频率等数据 ********************
    /**
     *  因为可能别人不一定会去实例化你的子类,或者其他类实现了点击方法不确定是哪一个,则可以通过runtime这个方法来解决
     */
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class selfClass = [self class];
        
        SEL oriSEL = @selector(sendAction:to:forEvent:);
        Method oriMethod = class_getInstanceMethod(selfClass, oriSEL);
        
        SEL cusSEL = @selector(mySendAction:to:forEvent:);
        Method cusMethod = class_getInstanceMethod(selfClass, cusSEL);
        
        BOOL addSucc = class_addMethod(selfClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
        if (addSucc) {
            class_replaceMethod(selfClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }else {
            method_exchangeImplementations(oriMethod, cusMethod);
        }
        
    });
    
    
    // ******************************************************************* 
}

交换方法只要有了定义,你调用的时候就会变成你交换了的方法
这里我们就定义了一个view_method来替换
注意:如果是在别的类中定义方法来代替,则必须是类方法;如果是在同一个类中,则可以有私有方法

接下来是跟踪方法

// 执行跟踪方法
    [self mySendAction:@selector(followAction:) to:self forEvent:UIEventTypeTouches];

这样子我就跟踪了followAction的方法,followAction一触发,跟踪方法也会跟着走

#pragma mark - 跟踪方法
/**
 *  跟交换方法一样,跟踪方法也需要在load方法里定义;
    当我们想要对一个方法在其原有的功能上增加功能,如果不想去实例化,或者说实现了很多点击方法不确定是哪一个,那我们可以通过runtime,在不碰源代码的基础上进行代码添加
 */
// 跟踪方法
- (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    BeeFollowViewController *followVC = [[BeeFollowViewController alloc]init];
    followVC.beeBlock = ^(NSInteger num){
        _Ji = num;
        NSLog(@"num = %ld",_Ji);
        if (!_beeTitleLabel) {
            _beeTitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 350, ScreenWidth, 30)];
            _beeTitleLabel.textAlignment = 1;
            [self.view addSubview:_beeTitleLabel];
        }
        _beeTitleLabel.text = [NSString stringWithFormat:@"你已经跳转过%ld次",_Ji];

    };
    [followVC followAction:_Ji];
}

这过程中我也写了个小demo,希望也能够帮助大家理解
https://github.com/iOSJYF/Garlic_runtime/tree/master/Garlic_WithRuntime

谢谢~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,690评论 0 9
  • 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的...
    西木阅读 30,548评论 33 466
  • 本文转载自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex阅读 749评论 0 1
  • 继上Runtime梳理(四) 通过前面的学习,我们了解到Objective-C的动态特性:Objective-C不...
    小名一峰阅读 744评论 0 3
  • Humpty DumptyHumpty Dumpty sat on a wall,Humpty Dumpty ha...
    涵宝妈妈么么哒阅读 365评论 0 0