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