修改代码:
提交过程(由编辑时极其不稳定的临时性Cache缓存状态送入本地端待同步的硬盘区域)。
推送过程:通过推送动作实现将本地端待同步的硬盘区域最新内容状态同步上传至远程端。
了解元类(Meta Class)。Objc中实例方法的调用是通过给实例对象发消息实现的,对于实例方法是可行的,但类方法呢?类方法的调用没有“实例对象”可以发送消息。所以Objc的设计者引入了元类概念:元类对象是描述类对象的类,每个类都有自己的元类,也就是类的isa指针指向的类,调用类方法实际上是给类的元类对象(isa指针指向的类)发送消息。上文中class_getClassMethod 实现是调用class_getInstanceMethod并且入参 cls->getMeta()获取元类(给类的元类对象(isa指针指向的类)发送消息)正是这个原因。
了解元类概念后,既然名称为load声明方法是类风格定义方法(囊括类风格方法的容器方法列表存在于ClassA类的元类中),通过获取ClassA类的元类下的方法列表:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Class metaClass = objc_getMetaClass("ClassA");
runTests(metaClass);
}
return 0;
}
void runTests (Class c ) {
unsigned int count;
Method *methods = class_copyMethodList(c, &count);
for (int i = 0; i < count; i++) {
Method method = methods[i];
SEL selector = method_getName(method);
NSString *name = NSStringFromSelector(selector);
NSLog(@"方法名:%@",name);
}
}
HookDemo[10929:9866637] 方法名:swizzle_load
HookDemo[10929:9866637] 方法名:load
现在成功的获取到了ClassA类相关的容器方法列表。容器方法列表中既然有名称load的方法名称元素 ,说明名称load方法元素是可以hook钩挂交换。新建ClassB类并在ClassB类中定义声明某个名称为load的成员方法并保证编译运行后先调用ClassB类的load声明方法(CompileSources顺序:ClassB类资源文件放在ClassA类的资源文件前面),然后在ClassB类中的load方法名称下钩挂hook ClassA类下的定义load方法的IMP实际执行区(注意:这里钩挂交换的是ClassA类的元类下的方法IMP):
+ (void) load {
NSString *className = @"ClassA";
Class class = NSClassFromString(className);
//钩挂交换的是ClassA类的元类下的方法
Class mateClass = objc_getMetaClass("ClassA");
//字段名部分+实际执行区Method的IMP部分
//原方法名称字段名的选择器盒和替换方法名称字段名的选择器盒//selector本身仅仅字段名部分
SEL originalSelector = @selector(load);
SEL swizzledSelector = @selector(swizzle_load);
// 原方法Method和替换方法Method(IMP部分所属Method实例)
Method originalMethod = class_getClassMethod(class, originalSelector);
Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
//如果当前类没有原方法的实现IMP,先调用class_addMethod来给原方法添加实现
BOOL didAddMethod = class_addMethod(mateClass,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {// 添加方法实现IMP成功后,替换方法实现
class_replaceMethod(mateClass,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else { // 有原方法,交换两个方法的实现
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
@end
运行后发现:ClassA类涉及的swizzle_load方法实例的执行IMP部分并未被调用,名称load方法的执行部分hook钩挂失败。
名称load方法钩挂Hook的特殊分析*