美文网首页
iOS-runtime的应用

iOS-runtime的应用

作者: Arthur澪 | 来源:发表于2020-03-11 17:05 被阅读0次

首先导入头文件#import <objc/runtime.h>

通过runtime的一系列方法,可以获取类的一些信息,
包括:属性列表,方法列表,成员变量列表,和遵循的协议列表。

1、获取列表
  • 获取属性列表

有时候会有这样的需求,我们需要知道当前类中每个属性的名字。

    unsigned int count;
    // 获取列表
    objc_property_t *propertyList = class_copyPropertyList([self class], &count);
    for (unsigned int i=0; i<count; i++) {
        // 获取属性名
        const char *propertyName = property_getName(propertyList[i]);
        // 打印
        NSLog(@"property-->%@", [NSString stringWithUTF8String:propertyName]);
    }
  • 获取方法列表
    Method *methodList = class_copyMethodList([self class], &count);
    for (unsigned int i; i<count; i++) {
        Method method = methodList[i];
        NSLog(@"method-->%@", NSStringFromSelector(method_getName(method)));
    }
  • 获取成员变量列表
    Ivar *ivarList = class_copyIvarList([self class], &count);
    for (unsigned int i; i<count; i++) {
        Ivar myIvar = ivarList[i];
        const char *ivarName = ivar_getName(myIvar);
        NSLog(@"Ivar---->%@", [NSString stringWithUTF8String:ivarName]);
    }
  • 获取协议列表
    __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(@"protocol---->%@", [NSString stringWithUTF8String:protocolName]);
    }
2、动态添加方法

核心方法:class_addMethod ()
首先从外部隐式调用一个不存在的方法:

// 隐式调用方法
[target performSelector:@selector(resolveAdd:) withObject:@"test"];

然后,在target对象内部重写拦截调用的方法,动态添加方法。

// 重写了拦截调用的方法,并返回YES
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    
    //给本类动态添加一个方法
    if ([NSStringFromSelector(sel) isEqualToString:@"resolveAdd:"]) {
        class_addMethod(self, sel, (IMP)runAddMethod, "v@:*");
    }
    return YES;
}
// 调用新增的方法
void runAddMethod(id self, SEL _cmd, NSString *string){
    NSLog(@"add C IMP ", string);  //withObject 参数
}

其中class_addMethod的四个参数分别是:
Class: cls 给哪个类添加方法,本例中是self
SEL name: 添加的方法,本例中是重写的拦截调用传进来的selector。
IMP imp: 方法的实现,C方法的方法实现可以直接获得。如果是OC方法,可以用+ (IMP)instanceMethodForSelector:(SEL)aSelector;获得方法的实现。
"v@:*":方法的签名,代表有一个参数的方法。

3、关联对象

现在你准备用一个系统的类,但是系统的类并不能满足你的需求,你需要额外添加一个属性。一般解决办法就是继承。
但是,只增加一个属性,就去继承一个类,觉得太麻烦类。
这个时候,runtime的关联属性就发挥它的作用了。在Category中添加属性。

//首先定义一个全局变量,用它的地址作为关联对象的key
static char associatedObjectKey;
//设置关联对象
objc_setAssociatedObject(target, &associatedObjectKey, @"添加的字符串属性", OBJC_ASSOCIATION_RETAIN_NONATOMIC); //获取关联对象
NSString *string = objc_getAssociatedObject(target, &associatedObjectKey);
NSLog(@"AssociatedObject = %@", string);

objc_setAssociatedObject的四个参数:
id object给谁设置关联对象。
const void *key关联对象唯一的key,获取时会用到。
id value关联对象。
objc_AssociationPolicy关联策略

4、动态重写方法

在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助Category重名方法之外,还有更加灵活的方法Method Swizzle
在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。
利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。

Method Swizzle指的是,改变一个已存在的选择器对应的实现过程。OC中方法的调用能够在运行时,改变类的调度表中选择器到最终函数间的映射关系。
每个类都有一个方法列表,存放着selector的名字及其方法实现的映射关系。IMP有点类似函数指针,指向具体的方法实现。
利用 method_exchangeImplementations来交换2个方法中的IMP。
利用 class_replaceMethod来修改类。
利用 method_setImplementation 来直接设置某个方法的IMP。

归根结底,都是偷换了selector的IMP

5、

相关文章

  • 壹、面试复习OC篇之runtime

    暂时copy过来,过后添加自己理解 原文地址:iOS-runtime通篇详解-上 iOS-runtime通篇详解-...

  • iOS-runtime的应用

    首先导入头文件#import 通过runtime的一系列方法,可以获取类的一些信...

  • iOS开发 runtime理解

    http://yimouleng.com/2015/05/28/ios-runtime/

  • IOS-Runtime应用场景

  • Runtime学习日程

    1、Runtime全方位装逼指南 2、Runtime窥探 (一)| 基本介绍 3、iOS-runtime通篇详解-...

  • iOS-runtime通篇详解-下

    上接上篇iOS-runtime通篇详解-上 原创内容,转载请注明出处: http://www.jianshu.co...

  • iOS-RunTime在实际开发中的应用

    什么是runtime? runtime 是 OC底层的一套C语言的API(引入 或...

  • iOS-RunTime

    https://www.jianshu.com/p/19f280afcb24 <简书 — 刘小壮> https:/...

  • iOS-Runtime

    一.什么是runtime? 话说每次面试都问runtime,你不会runtime能拿到像我66k的工资吗?所以关于...

  • iOS-runtime

    一、基本概念 Runtime基本是用C和汇编写的,可见苹果为了动态系统的高效而作出的努力。你可以在这里下到苹果维护...

网友评论

      本文标题:iOS-runtime的应用

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