Objective-C Runtime

runtime 使用场景
1、给分类添加“属性”
// 在分类的 .h 文件中声明“属性”

@property (nonatomic) NSInteger age;
// 在分类的 .m 实现以下两个方法

  • (void)setAge:(NSInteger)age{
    // 使用运行时关联对象,Person对象self强引用NSNumber对象@(age),并且设置标记为"age"(可以根据该标记来获取引用的对象age,标记可以为任意字符,只要setter和getter中的标记一致就可以)
    // 参数1:源对象
    // 参数2:关联时用来标记属性的key(因为可能要添加很多属性)
    // 参数3:关联的对象
    // 参数4:关联策略。assign,retain,copy对应的枚举值
    objc_setAssociatedObject(self, “age”, @(age), OBJC_ASSOCIATION_COPY_NONATOMIC);
    }

  • (NSInteger)age{
    // 根据"age"标识取Person对象self强引用的NSNumber对象@(age)
    // 参数1:源对象
    // 参数2:关联时用来标记属性的key(因为可能要添加很多属性)
    return [objc_getAssociatedObject(self, “age”) integerValue];
    }
    2、动态交换两个方法的实现

  • (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    Method originMethod = class_getInstanceMethod([self class], @selector(originFunction));
    Method customMethod = class_getInstanceMethod([self class], @selector(customFunction));
    // 尝试自定义方法实现添加到系统方法中
    BOOL addSuccess = class_addMethod([self class], @selector(originFunction), method_getImplementation(customMethod), method_getTypeEncoding(customMethod));
    if (addSuccess) {
    // 添加成功后,系统方法实现设置为自定义方法中
    class_replaceMethod([self class], @selector(customFunction), method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
    } else {
    method_exchangeImplementations(originMethod, customMethod);
    }
    });
    }
    3、动态添加方法
    如设置自定义类的实例为定时器的 target,动态为该类添加需要实际调用的实例方法。

  • (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval
    target:(id)aTarget
    selector:(SEL)aSelector
    userInfo:(id)userInfo
    repeats:(BOOL)repeats {
    Method targetMethod = class_getInstanceMethod([aTarget class], aSelector);
    if (!class_addMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod))) {
    class_replaceMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod));
    }
    BBTimerManager *manager = [BBTimerManager new];
    manager.bb_timer = [NSTimer scheduledTimerWithTimeInterval:interval target:manager selector:aSelector userInfo:userInfo repeats:repeats];
    return manager;
    }
    4、动态获取属性,可以用在 NSCoding 归档中,不用一个一个设置属性的解归档。

  • (void)encodeWithCoder:(NSCoder *)encoder {

    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([Movie class], &count);

    for (int i = 0; i < count; i++) {
    // 取出 i 位置对应的成员变量
    Ivar ivar = ivars[I];
    // 查看成员变量
    const char *name = ivar_getName(ivar);
    NSString *key = [NSString stringWithUTF8String:name];
    id value = [self valueForKey:key];
    // 归档
    [encoder encodeObject:value forKey:key];
    }
    free(ivars);
    }

  • (id)initWithCoder:(NSCoder *)decoder {
    if (self = [super init]) {

      unsigned int count = 0;
      Ivar *ivars = class_copyIvarList([Movie class], &count);
      
      for (int i = 0; i < count; i++) {
          // 取出i位置对应的成员变量
          Ivar ivar = ivars[I];
          // 查看成员变量
          const char *name = ivar_getName(ivar);
          NSString *key = [NSString stringWithUTF8String:name];
          id value = [decoder decodeObjectForKey:key];
          // 设置到成员变量身上
          [self setValue:value forKey:key];
      }
      free(ivars);
    

    }
    return self;
    }
    USB Microphone https://www.soft-voice.com/
    Wooden Speakers https://www.zeshuiplatform.com/
    亚马逊测评 www.yisuping.cn
    深圳网站建设www.sz886.com

上一篇:一年增加 1.2w 星,Dapr 能否引领云原生中间件的未来?


下一篇:Ubuntu 18.04下autoware 1.12 安装日志(含花屏解决方法)