美文网首页
Runtime 的一些用法

Runtime 的一些用法

作者: 再好一点点 | 来源:发表于2021-11-19 19:39 被阅读0次

一. 字典转模型

利用Runtime遍历所有的属性或者成员变量
利用KVC设值

+ (instancetype)yh_objectWithJson:(NSDictionary *)json
{
    id obj = [[self alloc] init];
    
    unsigned int count;
    Ivar *ivars = class_copyIvarList(self, &count);
    for (int i = 0; i < count; i++) {
        // 取出i位置的成员变量
        Ivar ivar = ivars[i];
        NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];
        [name deleteCharactersInRange:NSMakeRange(0, 1)];
        
        // 设值
        id value = json[name];
        if ([name isEqualToString:@"ID"]) {
            value = json[@"id"];
        }
        [obj setValue:value forKey:name];
    }
    free(ivars);
    
    return obj;
}

二. 设置和获取成员变量的值

object_setIvar要求对象类型,所以需要转换类型(__bridge id)(void *)10

    // 获取成员变量信息
    Ivar ageIvar = class_getInstanceVariable([Person class], "_age");
    NSLog(@"%s %s", ivar_getName(ageIvar), ivar_getTypeEncoding(ageIvar));

    //设置和获取成员变量的值
    Ivar nameIvar = class_getInstanceVariable([Person class], "_name");

    Person *person = [[Person alloc] init];
    object_setIvar(person, nameIvar, @"123");
    object_setIvar(person, ageIvar, (__bridge id)(void *)10);
    NSLog(@"%@ %d", person.name, person.age);
    
    // 成员变量的数量
    unsigned int count;
    Ivar *ivars = class_copyIvarList([Person class], &count);
    for (int i = 0; i < count; i++) {
        // 取出i位置的成员变量
        Ivar ivar = ivars[i];
        NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
    }
    free(ivars);

三. 查到私有成员变量以后设置私有成员变量

设置UITextField占位文字的颜色

    self.textField.placeholder = @"请输入用户名";
    [self.textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];

四. 替换方法实现

做了方法替换以后,当前类会清空已经缓存的方法列表
Person类

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

#import "Person.h"
@implementation Person
- (void)run
{
    NSLog(@"%s", __func__);
}

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

Car类

#import <Foundation/Foundation.h>
@interface Car : NSObject
@end

#import "Car.h"
@implementation Car
- (void)run
{
    NSLog(@"%s", __func__);
}
@end

同一个类的方法替换

        Person *person = [[Person alloc] init];
        Method runMethod = class_getInstanceMethod([Person class], @selector(run));
        Method testMethod = class_getInstanceMethod([Person class], @selector(test));
        method_exchangeImplementations(runMethod, testMethod);
        [person run];

不同类的方法替换

        Person *person = [[Person alloc] init];
        Method runMethod = class_getInstanceMethod([Person class], @selector(run));
        Method testMethod = class_getInstanceMethod([Car class], @selector(run));
        method_exchangeImplementations(runMethod, testMethod);
        [person run];

方法替换实际是替换的method_t结构里边的IMP(函数指针),所以不同类也可以进行替换。不过一般都是替换同一个类中的方法。

五. 创建类

object_setClass(person, [MJCar class]);修改对象的类对象,其实就是修改isa指针的指向。

void run(id self, SEL _cmd)
{
    NSLog(@"_____ %@ - %@", self, NSStringFromSelector(_cmd));
}

void createClass()
{
    // 创建类
    Class newClass = objc_allocateClassPair([NSObject class], "MJDog", 0);
    class_addIvar(newClass, "_age", 4, 1, @encode(int));
    class_addIvar(newClass, "_weight", 4, 1, @encode(int));
    class_addMethod(newClass, @selector(run), (IMP)run, "v@:");
    // 注册类
    objc_registerClassPair(newClass);
    
    Person *person = [[Person alloc] init];
    object_setClass(person, newClass);
    [person run];

    id dog = [[newClass alloc] init];
    [dog setValue:@10 forKey:@"_age"];
    [dog setValue:@20 forKey:@"_weight"];
    [dog run];

    NSLog(@"%@ %@", [dog valueForKey:@"_age"], [dog valueForKey:@"_weight"]);
    
    // 在不需要这个类时释放
//    objc_disposeClassPair(newClass);
}

六. 类相关用法

  1. 动态创建一个类(参数:父类,类名,额外的内存空间)
    a) Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)

  2. 注册一个类(要在类注册之前添加成员变量)
    a) void objc_registerClassPair(Class cls)

  3. 销毁一个类
    a) void objc_disposeClassPair(Class cls)

  4. 获取isa指向的Class
    a) Class object_getClass(id obj)

  5. 设置isa指向的Class
    a) Class object_setClass(id obj, Class cls)

  6. 判断一个OC对象是否为Class
    a) BOOL object_isClass(id obj)

  7. 判断一个Class是否为元类
    a) BOOL class_isMetaClass(Class cls)

  8. 获取父类
    a) Class class_getSuperclass(Class cls)

七. 成员变量

  1. 获取一个实例变量信息
    a) Ivar class_getInstanceVariable(Class cls, const char *name)

  2. 拷贝实例变量列表(最后需要调用free释放)
    a) Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

  3. 设置和获取成员变量的值
    a) void object_setIvar(id obj, Ivar ivar, id value)
    b) id object_getIvar(id obj, Ivar ivar)

  4. 动态添加成员变量(已经注册的类是不能动态添加成员变量的)
    a) BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

  5. 获取成员变量的相关信息
    a) const char *ivar_getName(Ivar v)
    a) const char *ivar_getTypeEncoding(Ivar v)

八. 属性

  1. 获取一个属性
    a) objc_property_t class_getProperty(Class cls, const char *name)

  2. 拷贝属性列表(最后需要调用free释放)
    a) objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

  3. 动态添加属性
    a) BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
    unsigned int attributeCount)

  4. 动态替换属性
    a) void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
    unsigned int attributeCount)

  5. 获取属性的一些信息
    a) const char *property_getName(objc_property_t property)
    b) const char *property_getAttributes(objc_property_t property)

九. 方法

  1. 获得一个实例方法、类方法
    a) Method class_getInstanceMethod(Class cls, SEL name)
    b) Method class_getClassMethod(Class cls, SEL name)

  2. 方法实现相关操作
    a) IMP class_getMethodImplementation(Class cls, SEL name)
    b) IMP method_setImplementation(Method m, IMP imp)
    c) void method_exchangeImplementations(Method m1, Method m2)

  3. 拷贝方法列表(最后需要调用free释放)
    a) Method *class_copyMethodList(Class cls, unsigned int *outCount)

  4. 动态添加方法
    a) BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

  5. 动态替换方法
    a) IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

  6. 获取方法的相关信息(带有copy的需要调用free去释放)
    a) SEL method_getName(Method m)
    b) IMP method_getImplementation(Method m)
    c) const char *method_getTypeEncoding(Method m)
    d) unsigned int method_getNumberOfArguments(Method m)
    e) char *method_copyReturnType(Method m)
    f) char *method_copyArgumentType(Method m, unsigned int index)

  7. 选择器相关
    a) const char *sel_getName(SEL sel)
    b) SEL sel_registerName(const char *str)

  8. 用block作为方法实现
    a) IMP imp_implementationWithBlock(id block)
    b) id imp_getBlock(IMP anImp)
    c) BOOL imp_removeBlock(IMP anImp)

相关文章

  • RunTime的一些用法

    RunTime简介 RunTime简称运行时.OC就是运行时机制,其中最主要的是消息机制 对于OC来说,在编译的时...

  • Runtime 的一些用法

    一. 字典转模型 利用Runtime遍历所有的属性或者成员变量利用KVC设值 二. 设置和获取成员变量的值 obj...

  • iOS面试点文章链接

    runtime基础方法、用法、消息转发、super: runtime 完整总结 runloop源码、runloop...

  • Runtime 从NullSafe源码看消息转发 机制

    开篇 马上就要年底了再码一波,自己总结一下Runtime,打算总结一下Runtime的各种用法,结合一些常见的源码...

  • iOS-runtime相关

    本篇涵盖runtime的解析、应用等. 1.runtime快速入门和实战2.Runtime 10种用法(没有比这更...

  • runtime的用法

    1.使用runtime改变变量值 2.使用runtime交换方法 3.使用runtime添加方法 4.使用runt...

  • runtime的用法

    最近在研究runtime 主要是想好好的装一波 无奈 看过了 唐巧大大的runtime介绍 看的我是脑袋直疼,看来...

  • RunTime的用法

    RunTime简介## 刚入行的时候,经常听到某些自称大神的人说runtime怎么怎么强大怎么怎么牛逼,我总是被忽...

  • RunTime用法

    一、什么是RunTime iOS开发过程中,我们一直在与Runtime打交道,可什么是Runtime呢? 对比C语...

  • runtime用法

    在之前学习runtime的过程中,我发现方法交换有两种写法,一开始对对一种写法不太能理解,后来自己写demo来试验...

网友评论

      本文标题:Runtime 的一些用法

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