• iOS开发黑科技之runtime


    iOS 开发之黑科技—runtime

    runtime其实就是oc底层的一套C语音的API

    调用方法的本质就是发消息,

    1、动态交换两个方法的实现(特别是交换系统自动的方法)

    2、动态添加对象的成员变量和成员方法

    3、获得某个类的所有成员方法、所有成员变量

    注意:

    对于一般OC代码的method swizzling, 在load方法中执行即可. 而Swift没有load, 所以要在initialize中执行.

    应用

    1、block的实现原理

    2、拦截系统自带的方法调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    + (void)load {
    // 获取两个类的类方法
    Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
    Method m2 = class_getClassMethod([UIImage class], @selector(xh_imageNamed:));
    // 开始交换方法实现
    method_exchangeImplementations(m1, m2);
    }
    + (UIImage *)xh_imageNamed:(NSString *)name {
    return [UIImage xh_imageNamed:name];
    }

    3、实现类别也可以增加属性

    1
    2
    3
    4
    5
    6
    7
    -(NSString *)name{
    return objc_getAssociatedObject(self, @"nameKey");
    }
    -(void)setName:(NSString *)name{
    objc_setAssociatedObject(self, @"nameKey", name , OBJC_ASSOCIATION_COPY_NONATOMIC);
    }

    4、实现nscodeing的自动归档和自动接档

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    - (void)decode:(NSCoder *)aDecoder {
    // 一层层父类往上查找,对父类的属性执行归解档方法
    Class c = self.class;
    while (c &&c != [NSObject class]) {
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList(c, &outCount);
    for (int i = 0; i < outCount; i++) {
    Ivar ivar = ivars[i];
    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
    id value = [aDecoder decodeObjectForKey:key];
    [self setValue:value forKey:key];
    }
    }
    }
    - (void)encode:(NSCoder *)aCoder {
    // 一层层父类往上查找,对父类的属性执行归解档方法
    Class c = self.class;
    while (c &&c != [NSObject class]) {
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([self class], &outCount);
    for (int i = 0; i < outCount; i++) {
    Ivar ivar = ivars[i];
    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
    // 如果有实现该方法再去调用
    id value = [self valueForKeyPath:key];
    [aCoder encodeObject:value forKey:key];
    }
    }
    }

    5、实现字典和模型的自动转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32大专栏  iOS开发黑科技之runtimev>
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    - (void)setDict:(NSDictionary *)dict {
    Class c = self.class;
    while (c &&c != [NSObject class]) {
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList(c, &outCount);
    for (int i = 0; i < outCount; i++) {
    Ivar ivar = ivars[i];
    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
    // 成员变量名转为属性名(去掉下划线 _ )
    key = [key substringFromIndex:1];
    // 取出字典的值
    id value = dict[key];
    // 如果模型属性数量大于字典键值对数理,模型属性会被赋值为nil而报错
    if (value == nil) continue;
    // 获得成员变量的类型
    NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
    // 如果属性是对象类型
    NSRange range = [type rangeOfString:@"@"];
    if (range.location != NSNotFound) {
    // 那么截取对象的名字(比如@"Dog",截取为Dog)
    type = [type substringWithRange:NSMakeRange(2, type.length - 3)];
    // 排除系统的对象类型
    if (![type hasPrefix:@"NS"]) {
    // 将对象名转换为对象的类型,将新的对象字典转模型(递归)
    Class class = NSClassFromString(type);
    value = [class objectWithDict:value];
    }else if ([type isEqualToString:@"NSArray"]) {
    // 如果是数组类型,将数组中的每个模型进行字典转模型,先创建一个临时数组存放模型
    NSArray *array = (NSArray *)value;
    NSMutableArray *mArray = [NSMutableArray array];
    // 获取到每个模型的类型
    id class ;
    if ([self respondsToSelector:@selector(arrayObjectClass)]) {
    NSString *classStr = [self arrayObjectClass];
    class = NSClassFromString(classStr);
    }else {
    NSLog(@"数组内模型是未知类型");
    return;
    }
    // 将数组中的所有模型进行字典转模型
    for (int i = 0; i < array.count; i++) {
    [mArray addObject:[class objectWithDict:value[i]]];
    }
    value = mArray;
    }
    }
    // 将字典中的值设置到模型上
    [self setValue:value forKeyPath:key];
    }
    free(ivars);
    c = [c superclass];
    }
    }
    + (instancetype )objectWithDict:(NSDictionary *)dict {
    NSObject *obj = [[self alloc]init];
    [obj setDict:dict];
    return obj;
    }

    这两个都是

    Ivar * ivars = class_copyIvarList(self.class, &outCount);
    就不用一个一个属性写了。
    再说一下归档解档

    如果不是系统的类,要进行归档解档要遵守协议,和实现协议中的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    -(void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.name forKey:@"name"];
    }
    -(id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
    self.name = [aDecoder decodeObjectForKey:@"name"];
    }
    ⬅️ Go back
  • 相关阅读:
    Hive中频繁报警的问题
    Hadoop中Namenode的HA查询和切换
    昨天面试遇到的一道C语言题
    【转】MapReduce的优化
    关于linux修改max user processes limits的问题
    Hadoop-2.6.0安装文档
    C#使用RabbitMQ
    windows配置Erlang环境
    【转】linux查看及修改文件权限以及相关
    (转)C#图解—PictureBox.SizeMode 属性
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12284308.html
Copyright © 2020-2023  润新知