Runtime(七)、runtime应用

260 阅读2分钟

成员变量

    // 获取成员变量信息
    Ivar ageIvar = class_getInstanceVariable([MJPerson class], "_age");
    NSLog(@"%s %s", ivar_getName(ageIvar), ivar_getTypeEncoding(ageIvar));
    
    // 设置和获取成员变量的值
    Ivar nameIvar = class_getInstanceVariable([MJPerson class], "_name");

    MJPerson *person = [[MJPerson 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([MJPerson 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);

  • object_setIvar(person, ageIvar, (__bridge id)(void *)10); 这个方法传的值,必须是OC类型。当成员变量是基本类型时,比如这里是int类型,不能是NSNumber类型@(10),必须用 void *并桥接成OC类型。不能用int *桥接
  • class_copyIvarList创建出来的必须释放free(ivars);

MJPerson *person = [[MJPerson alloc] init];
    [person run];
    
    object_setClass(person, [MJCar class]);
    [person run];
    
    NSLog(@"%d %d %d",
          object_isClass(person),
          object_isClass([MJPerson class]),
          object_isClass(object_getClass([MJPerson class]))
          );
    
    //        NSLog(@"%p %p", object_getClass([MJPerson class]), [MJPerson class]);

        // 创建类
        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);
        
        MJPerson *person = [[MJPerson 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);

  • 添加成员变量和方法,必须在注册类之前。
  • 不需要这个类的时要释放
  • objc_allocateClassPair从名字可以看出(Pair),创建的是两个对象,类对象和元类对象。

字典转模型

#import "NSObject+Json.h"
#import <objc/runtime.h>

@implementation NSObject (Json)

+ (instancetype)mj_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;
}

@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        
         //字典转模型
        NSDictionary *json = @{
                               @"id" : @20,
                               @"age" : @20,
                               @"weight" : @60,
                               @"name" : @"Jack"
//                               @"no" : @30
                               };

        MJPerson *person = [MJPerson mj_objectWithJson:json];

        [MJCar mj_objectWithJson:json];

        MJStudent *student = [MJStudent mj_objectWithJson:json];

        NSLog(@"123");
    }
    return 0;
}

属性

方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MJPerson *person = [[MJPerson alloc] init];
        
        Method runMethod = class_getInstanceMethod([MJPerson class], @selector(run));
        Method testMethod = class_getInstanceMethod([MJPerson class], @selector(test));
        method_exchangeImplementations(runMethod, testMethod);

        [person run];
    }
    return 0;
}

void myrun()
{
    NSLog(@"---myrun");
}

void test()
{
    MJPerson *person = [[MJPerson alloc] init];
    
    //        class_replaceMethod([MJPerson class], @selector(run), (IMP)myrun, "v");
    
    
    class_replaceMethod([MJPerson class], @selector(run), imp_implementationWithBlock(^{
        NSLog(@"123123");
    }), "v");
    
    [person run];
}

具体应用

设置UITextField的placeholder的字体颜色 正常:

    NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
    attrs[NSForegroundColorAttributeName] = [UIColor redColor];
    self.textField.attributedPlaceholder = [[NSMutableAttributedString alloc] initWithString:@"请输入用户名" attributes:attrs];

但是也可以,找到这个属性,查看它的类型,然后通过runtime设置。

    unsigned int count;
    Ivar *ivars = class_copyIvarList([UITextField 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);
Ivar ivar = class_getInstanceVariable([UITextField class],"_placeholderLabel");
    NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
    
    
    NSLog(@"%@",class_getSuperclass(NSClassFromString(@"UITextFieldLabel")));
    self.textField.placeholder = @"请输入用户名";
    
    
//    NSLog(@"%@",class_getSuperclass([UITextFieldLabel class]));//报错,这个类是前向声明。我们必须找到它的父类
//
//    //找到UITextFieldLabel的父类
//    NSLog(@"%@",class_getSuperclass(NSClassFromString(@"UITextFieldLabel")));
//
//
//    [self.textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
    

    UILabel *placeholderLabel = [self.textField valueForKeyPath:@"_placeholderLabel"];
    placeholderLabel.textColor = [UIColor redColor];

13.0后不允许用KVC方式,设置其成员变量了。运行崩溃。 用下面的方法:

    Ivar ivar = class_getInstanceVariable([UITextField class],"_placeholderLabel");
    UILabel *label = object_getIvar(self.textField,ivar);
    label.textColor = [UIColor redColor];