zoukankan      html  css  js  c++  java
  • iOS----runtime 运行时机制04--(方法交换)

    1、同一个类中两个方法交换

    交换方法

    - (void)setBadgeValue:(NSString *)badgeValue 和 - (void)wb_setBadgeValue:(NSString *)badgeValue的实现
    @implementation UITabBarItem (BadgeValueImage)
    
    + (void)load{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Class clazz = [self class];
            
            // 获取到原来的方法与需要交互的SEL
            SEL originalSelector = @selector(setBadgeValue:);
            SEL swizzledSelector = @selector(wb_setBadgeValue:);
            
            // 通过SEL 获取到类身上的Method
            Method originalMethod = class_getInstanceMethod(clazz, originalSelector);
            Method swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector);
            
            // 向类身上添加方法
            BOOL result = class_addMethod(clazz, swizzledSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
            
            if (result) {
                // 如果添加成功就替换方法实现
                class_replaceMethod(clazz, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
            }else{
                // 没有添加成功,直接交换方法实现
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
        });
    }
    
    - (void)wb_setBadgeValue:(NSString *)badgeValue{
        //调用父类
        [self wb_setBadgeValue:badgeValue];
        
        // 实现逻辑
        // 如果badgeValue为nil 的话。直接返回
        if(!badgeValue){
            return;
        }
        
        // 我们直接能够拿到的就是WBTabBar
        UITabBarController *target = [self valueForKeyPath:@"_target"];
        
        for (UIView *tabBarChild in target.tabBar.subviews) {
            //找UITabBarButton
            if ([tabBarChild isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
                for (UIView *tabBarButtonChild in tabBarChild.subviews) {
                    if ([tabBarButtonChild isKindOfClass:NSClassFromString(@"_UIBadgeView")]) {
                        for (UIView *badgeViewChild in tabBarButtonChild.subviews) {
                            if ([badgeViewChild isKindOfClass:NSClassFromString(@"_UIBadgeBackground")]) {
                                //NSLog(@"终于找到你,还好没放弃");
                                unsigned int count;//获取完成之后,count的值就代码当前类身上成员变量的个数
                                
                                //获取类身上的成员变量
                                Ivar *vars = class_copyIvarList(NSClassFromString(@"_UIBadgeBackground"), &count);
                                //遍历查看
                                for (int i=0; i<count; i++) {
                                    Ivar var = vars[i];
                                    
                                    //获取var的名字
                                    NSString *name = [NSString stringWithCString:ivar_getName(var) encoding:NSUTF8StringEncoding];
                                    //获取类型
                                    NSString *type = [NSString stringWithCString:ivar_getTypeEncoding(var) encoding:NSUTF8StringEncoding];
                                    
                                    NSLog(@"%@=====%@",name,type);
                                    //
                                    if ([name isEqualToString:@"_image"]) {
                                        //通过kvc赋值
                                        [badgeViewChild setValue:[UIImage imageNamed:self.badgeImageName] forKeyPath:name];
                                    }
                                }
                                //释放内存
                                free(vars);
                            }
                        }
                    }
                }
            }
        }
    }

    2、交换两个类中某个方法的实现

    交换 Person类中 - (void)personEat; 和Dog类中 - (void)dogEat; 中的实现

    Person.h

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    
    - (void)personEat;
    
    
    @end

    person.m

    #import "Person.h"
    #import "Dog.h"
    #import <objc/runtime.h>
    
    @implementation Person
    
    + (void)load{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            //1,拿着class
            Class personClass = [self class];
            Class dogClass = [Dog class];
            
            //2.获取两个方法的sel
            SEL originalSEL = @selector(personEat);
            SEL swizzledSEL = @selector(dogEat);
            
            //3.通过sel获取到class身上的method
            Method originalMethod = class_getInstanceMethod(personClass, originalSEL);
            Method swizzledMethod = class_getInstanceMethod(dogClass, swizzledSEL);
            
            //4执行方法添加-->添加方法是添加的其他类里面的方
            BOOL result = class_addMethod(personClass, swizzledSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
            
            //5如果添加成功,就把添加的方法的实现与原来的方法进行替换
            if (result) {
                class_replaceMethod(personClass, originalSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
                
            }else{
                //6.如果添加不成功,就直接交换方法实现
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
        });
    }
    
    - (void)personEat{
        NSLog(@"人在吃东西");
    }
    
    @end

    Dog.h

    #import <Foundation/Foundation.h>
    
    @interface Dog : NSObject
    
    - (void)dogEat;
    
    @end

    Dog.m

    #import "Dog.h"
    
    @implementation Dog
    
    - (void)dogEat{
        NSLog(@"狗在吃东西");
    }
    
    @end

    此时调用 

        Person *p = [[Person alloc]init];

        [p personEat];

    结果会是:狗在吃东西

  • 相关阅读:
    HttpService与WebService的差异
    在oracle中varchar和varchar2有什么区别?
    物联网项目的思考
    配置JDK-Java运行环境
    浅谈DDD
    参数化SQL语句
    OneNote无法同时设置中英文字体设置解决办法
    Oracle OCI-22053:溢出错误解决方法
    oracle 日期格式
    Visual Studio 2017各版本安装包离线下载
  • 原文地址:https://www.cnblogs.com/jiqiaochun/p/4749727.html
Copyright © 2011-2022 走看看