在逆向工程中,利用runtime可以动态获取类和属性,绑定属性,替换方法的实现。
KVC
可以通过直接获取类的私有属性。
MyClass *myClass = [[MyClass alloc] init];
//KVC
NSString* property = [myClass valueForKey:@"_property"];
NSLog(@"property: %@", property);
Ivar ivar = class_getInstanceVariable(objc_getClass("MyClass"), "_property");
if(ivar){
NSString* ivarProperty = (__bridge NSString *)(*(void**)((__bridge void*)myClass + ivar_getOffset(ivar)));
NSLog(@"ivarProperty: %@", ivarProperty);
}
关联对象AssociatedObject
在对象实例化后是不能动态添加属性的,除非是动态创建一个类。要为已存在的对象添加一个属性,可以通过关联对象(AssociatedObject)添加。关联对象相当于把一个对象关联到另一个对象上,关联后可以随时获取该关联对象,在对象被销毁时会移除所有关联对象。
objc_setAssociatedObject给myClass对象关联一个字符串
objc_getAssociatedObject获取myClass对象的字符串
第二个参数作为关联对象的唯一标识,有3种标识方法
//1,第一种标识方法
//static const void *kAssociatedKey = &kAssociatedKey;
objc_setAssociatedObject(myClass, kAssociatedKey, @"AssociatedObject1", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
NSString* associatedString = objc_getAssociatedObject(myClass, kAssociatedKey);
NSLog(@"associatedString: %@", associatedString);
//第二种标识方法
//static void *kExampleDoubleKey;
objc_setAssociatedObject(myClass, &kExampleDoubleKey, @"AssociatedObject2", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
associatedString = objc_getAssociatedObject(myClass, &kExampleDoubleKey);
NSLog(@"associatedString: %@", associatedString);
//第三种标识方法
objc_setAssociatedObject(myClass, @selector(myProperty), @"AssociatedObject3", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
associatedString = objc_getAssociatedObject(myClass, @selector(myProperty));
NSLog(@"associatedString: %@", associatedString);
交换方法 method Swizzling
对某方法进行拦截和修改来修改程序的逻辑和数据。
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
//源方法IMP
SEL originalSelector = @selector(viewWillAppear:);
//目标方法IMP
SEL swizzledSelector = @selector(ms_viewWillAppear:);
//源方法名
Method originalMethod = class_getInstanceMethod(class, originalSelector);
//目标方法名
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
//给类添加方法以及IMP
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
//给类的方法替换IMp
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
- (void)ms_viewWillAppear:(BOOL)animated {
[self ms_viewWillAppear:animated];
NSLog(@"viewWillAppear: %@", self);
}