美文网首页iOS开发笔记
Runtime动态创建一个类和修改方法的操作

Runtime动态创建一个类和修改方法的操作

作者: 祥子_HelloWorld | 来源:发表于2019-08-08 18:38 被阅读0次

我们都知道Objective-C是一门动态语言,它的动态性一方面就体现在了runtime上。

接下来我们就来看一下,通过runtime来动态的创建一个类,并且给类添加属性和方法,并且还能给已有的类修改、替换方法的实现。

动态的创建一个类的步骤:
  1. 创建一个类
  2. 添加属性(一定要在注册前添加)
  3. 注册这个类
  4. 添加方法
  5. 销毁这个类
-(void)createClass
{
    //创建一个新类 MyClass
    Class myClass = objc_allocateClassPair([NSObject class], "MyClass", 0);
    //添加ivar
    //@encode(aType):返回该类型的C字符串
    class_addIvar(myClass, "_address", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
    class_addIvar(myClass, "_age", sizeof(NSUInteger), log2(sizeof(NSUInteger)), @encode(NSUInteger));
    //注册类
    objc_registerClassPair(myClass);
    //创建实例
    id object = [[myClass alloc] init];
    //为ivar设置值
    [object setValue:@"china" forKey:@"address"];
    [object setValue:@20 forKey:@"age"];
    NSLog(@"address=%@,age=%@",[object valueForKey:@"address"],[object valueForKey:@"age"]);
    
    //添加方法
    Class class = [self class];
    SEL selfInsMethod1 = @selector(instanceMethod1);
    Method insMethod1 = class_getInstanceMethod(class, selfInsMethod1);
    IMP impInsMethod1 = method_getImplementation(insMethod1);
    const char *typeInsMethod1 = method_getTypeEncoding(insMethod1);
    SEL selfNewInsMethod = @selector(newInsMethod);
    BOOL isInsAdded = class_addMethod(myClass, selfNewInsMethod, impInsMethod1, typeInsMethod1);
    if (!isInsAdded) {
        NSLog(@"新实例方法添加失败!");
    }
    [object performSelector:selfNewInsMethod];
    
    //当类或者它的子类的实例还存在,则不能调用objc_disposeClassPair方法
    object = nil;
    //销毁
    objc_disposeClassPair(myClass);
    
}

-(void)instanceMethod1
{
    NSLog(@"%s",__func__);
}

-(void)instanceMethod2
{
    NSLog(@"%s",__func__);
}

+ (void)classMethod1
{
    NSLog(@"%s",__func__);
}

+ (void)classMethod2
{
    NSLog(@"%s",__func__);
}
Method Swizzling

Method Swizzling是iOS开发的黑魔法,可以灵活的对方法进行各种操作。

  • 类第一次被调用加载的时候+ (void)load才会被调用,有且只有一次被调用。
  • 只在 +load 中执行 swizzling 才是安全的。
+ (void)load
{
    NSLog(@"%s",__func__);

    //1、获取当前类名
    Class class = [self class];
    //2、获取方法名(选择器)
    SEL selfInsMethod1 = @selector(instanceMethod1);
    SEL selfInsMethod2 = @selector(instanceMethod2);
    SEL selfClassMethod1 = @selector(classMethod1);
    SEL selfClassMethod2 = @selector(classMethod2);
    //3、根据方法名获取方法对象
    Method insMethod1 = class_getInstanceMethod(class, selfInsMethod1);
    Method insMethod2 = class_getInstanceMethod(class, selfInsMethod2);
    Method classMethod1 = class_getClassMethod(class, selfClassMethod1);
    Method classMethod2 = class_getClassMethod(class, selfClassMethod2);
    
    //4、交换实例方法的实现
    if (!insMethod1 || !insMethod2) {
        NSLog(@"实例方法实现运行时交换失败!");
        return;
    }
    method_exchangeImplementations(insMethod1, insMethod2);
    //5、交换类方法的实现
    if (!classMethod1 || !classMethod2) {
        NSLog(@"类方法实现运行时交换失败!");
        return;
    }
    method_exchangeImplementations(classMethod1, classMethod2);
    //类方法和实例方法也可以交换,前提是没有代码错误
 
    /* 重设类中方法的实现 */
    //获取方法的实现
    IMP impInsMethod1 = method_getImplementation(insMethod1);
    IMP impInsMethod2 = method_getImplementation(insMethod2);
    IMP impClassMethod1 = method_getImplementation(classMethod1);
    IMP impClassMethod2 = method_getImplementation(classMethod2);
    //重新设置方法的实现
    method_setImplementation(insMethod1, impInsMethod2);
    method_setImplementation(insMethod2, impInsMethod1);
    method_setImplementation(classMethod1, impClassMethod2);
    method_setImplementation(classMethod2, impClassMethod1);
    
    //获取方法编码类型
    const char *typeInsMethod1 = method_getTypeEncoding(insMethod1);
    const char *typeInsMethod2 = method_getTypeEncoding(insMethod2);
    const char *typeClassMethod1 = method_getTypeEncoding(insMethod1);
    const char *typeClassMethod2 = method_getTypeEncoding(insMethod2);
    //替换实例方法
    class_replaceMethod(class, selfInsMethod1, impInsMethod2, typeInsMethod2);
    class_replaceMethod(class, selfInsMethod2, impInsMethod1, typeInsMethod1);
    //尝试替换类方法的实现,实际结果是无效的,class_replaceMethod只能替换实例方法的实现
    class_replaceMethod(class, selfClassMethod1, impClassMethod2, typeClassMethod2);
    class_replaceMethod(class, selfClassMethod2, impClassMethod1, typeClassMethod1);

    
    /* 为类添加新的实例方法和类方法 */
    SEL selfNewInsMethod = @selector(newInsMethod);
    BOOL isInsAdded = class_addMethod(class, selfNewInsMethod, impInsMethod1, typeInsMethod1);
    if (!isInsAdded) {
        NSLog(@"新实例方法添加失败!");
    }
}

相关文章

  • ios runtime

    什么是runtime runtime运用 在程序运行过程中,动态的创建类,动态添加、修改这个类的属性和方法 遍历一...

  • Runtime的定义

    runtime基本作用 在程序运行过程中,动态的创建类,动态添加、修改这个类的方法和属性 遍历一个类的所有成员变量...

  • Runtime 04 - 应用(动态创建类、交换方法)

    Runtime 04 - 应用(动态创建类、交换方法) 动态创建类 需要创建的类结构如下 动态创建类的示例 先定义...

  • Runtime动态创建一个类和修改方法的操作

    我们都知道Objective-C是一门动态语言,它的动态性一方面就体现在了runtime上。 接下来我们就来看一下...

  • 三十一、Runtime之(十四)Runtime相关API

    Runtime相关API01—类 1.动态创建一个类,并为该类添加成员变量和方法。 Runtime相关API02 ...

  • runtime相关

    修改系统方法 动态添加方法 动态给系统类添加属性(给分类添加属性) runtime+kvc 转换模型

  • iOS RunTime 理解

    可以遍历对象的属性 可以动态的添加、修改属性,动态添加、修改、替换方法,动态添加、修改、替换协议 可以动态创建类、...

  • KVO内部实现原理

    动态创建一个子类,注册 修改被观察者的类型,修改isa指针 添加set方法 动态绑定属性 使用 类:方法调用 对象...

  • iOS 拦截所有按钮的点击事件

    引言 1、在程序运行过程中,动态的创建类,动态添加、修改这个类的属性和方法; 2、遍历一个类中所有的成员变量、属性...

  • iOS 底层 - 名词解析

    目录 前言 名词解析 OC消息传递和转发机制 Runtime runtime动态创建类 Runloop Metho...

网友评论

    本文标题:Runtime动态创建一个类和修改方法的操作

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