美文网首页
iOS 中runtime的用法

iOS 中runtime的用法

作者: Bearger | 来源:发表于2017-04-26 20:05 被阅读16次

    交换方法

    • 开发使用场景:系统自带的方法功能不够,给系统自带的方法扩展一些功能,并且保持原有的功能。
    • 方式一:继承系统的类,重写方法.
    • 方式二:使用runtime,交换方法.
    @implementation ViewController
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        // 需求:给imageNamed方法提供功能,每次加载图片就判断下图片是否加载成功。
        // 步骤一:先搞个分类,定义一个能加载图片并且能打印的方法+ (UIImage *)xmg_imageNamed:(NSString *)imageName;
        // 步骤二:交换imageNamed和xmg_imageNamed的实现,就能调用xmg_imageNamed,间接调用xmg_imageNamed的实现。
        UIImage *image = [UIImage imageNamed:@"123"];
    
             imageNamed:
         实现方法:底层调用PH_imageNamed
    
         本质:交换两个方法的实现imageNamed和PH_imageNamed方法
         调用imageNamed其实就是调用PH_imageNamed
    
         imageNamed加载图片,并不知道图片是否加载成功
         以后调用imageNamed的时候,就知道图片是否加载
    }
    
    @end
    
    
    @implementation UIImage (Image)
    // 加载分类到内存的时候调用
    + (void)load
    {
        // 交换方法实现,方法都是定义在类里面
        // class_getMethodImplementation:获取方法实现
        // class_getInstanceMethod:获取对象
        // class_getClassMethod:获取类方法
        // IMP:方法实现
    
        // imageNamed
        // Class:获取哪个类方法
        // SEL:获取方法编号,根据SEL就能去对应的类找方法
    
        Method imageNameMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
    
        Method PH_imageNameMethod = class_getClassMethod([UIImage class], @selector(PH_imageNamed:));
    
        // 交换方法实现
        method_exchangeImplementations(imageNameMethod, PH_imageNameMethod);
    }
    
    
    
    }
    
    // 不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super.
    
    // 既能加载图片又能打印
    + (UIImage *)PH_imageNamed:(NSString *)imageName
    {
        // 加载图片
        UIImage *image = [UIImage PH_imageNamed:imageName];
        // 2.判断功能
        if (image == nil) {
            NSLog(@"加载为空");
        }
        return image;
    }
    
    
    @end
    

    动态添加方法
    开发使用场景:如果一个类方法非常多,加载类到内存的时候也比较耗费资源,需要给每个方法生成映射表,可以使用动态给某个类,添加方法解决。

    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    
        Person *p = [[Person alloc] init];
    
        // 默认person,没有实现eat方法,可以通过performSelector调用,但是会报错。
        // 动态添加方法就不会报错
        [p performSelector:@selector(eat)];
    
    }
    
    
    @end
    
    @implementation Person
    // void(*)()
    // 默认方法都有两个隐式参数,
    //默认一个方法都有两个参数,self,_cmd,隐式参数
    // self:方法调用者
    // _cmd:调用方法的编号
    void eat(id self,SEL sel)
    {
        NSLog(@"%@ %@",self,NSStringFromSelector(sel));
    }
    
    // 当一个对象调用未实现的方法,会调用这个方法处理,并且会把对应的方法列表传过来.
    // 刚好可以用来判断,未实现的方法是不是我们想要动态添加的方法
    
    <!--动态添加方法,首先实现这个resolveInstanceMethod-->
    <!-- resolveInstanceMethod调用:当调用了没有实现的方法没有实现就会调用resolveInstanceMethod-->
    <!-- resolveInstanceMethod作用:就知道哪些方法没有实现,从而动态添加方法-->
    <!-- sel:没有实现方法-->
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
    
        if (sel == @selector(eat)) {
            // 动态添加eat方法
    
            // 第一个参数:给哪个类添加方法
            // 第二个参数:添加方法的方法编号
            // 第三个参数:添加方法的函数实现(函数地址)
            // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
            class_addMethod(self, @selector(eat), eat, "v@:");
    
        }
    
        return [super resolveInstanceMethod:sel];
    }
    @end
    

    给分类添加属性

    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    
        // 给系统NSObject类动态添加属性name
    
        NSObject *objc = [[NSObject alloc] init];
        objc.name = @"abc";
        NSLog(@"%@",objc.name);
    }
    @end
    
    
    // 定义关联的key
    static const char *key = "name";
    
    - (void)setName:(NSString *)name
    {
        // 添加属性,跟对象
        // 给某个对象产生关联,添加属性
        // object:给哪个对象添加属性
        // key:属性名,根据key去获取关联的对象 ,void * == id
        // value:关联的值
        // policy:策略
    
        objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    - (NSString *)name
    {
    
        return objc_getAssociatedObject(self, @"name");
    }
    

    相关文章

      网友评论

          本文标题:iOS 中runtime的用法

          本文链接:https://www.haomeiwen.com/subject/oqswzttx.html