Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 为什么ARC在使用objc运行时库中的class_replaceMethod滑动函数时会导致EXC_BAD_访问?_Objective C_Automatic Ref Counting_Hook_Objective C Runtime_Method Swizzling - Fatal编程技术网

Objective c 为什么ARC在使用objc运行时库中的class_replaceMethod滑动函数时会导致EXC_BAD_访问?

Objective c 为什么ARC在使用objc运行时库中的class_replaceMethod滑动函数时会导致EXC_BAD_访问?,objective-c,automatic-ref-counting,hook,objective-c-runtime,method-swizzling,Objective C,Automatic Ref Counting,Hook,Objective C Runtime,Method Swizzling,我需要替换特定Objective-C类的一些方法实现。objc/运行时库中的一组函数能够做到这一点。为了简化问题,我只需编写一个最简单的示例代码,如下所示: #import <Foundation/Foundation.h> #import <objc/runtime.h> @interface MyClass : NSObject - (void) func; @end @implementation MyClass - (void) func { NSL

我需要替换特定Objective-C类的一些方法实现。objc/运行时库中的一组函数能够做到这一点。为了简化问题,我只需编写一个最简单的示例代码,如下所示:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface MyClass : NSObject
- (void) func;
@end

@implementation MyClass

- (void) func {
    NSLog(@"Hello from MyClass!");
}

@end

//Original implementation of the method
static IMP gOriginalFunc = nil;

//Hook function that will take place of the original method
void HookFunc(id self, SEL _cmd)
{
    NSLog(@"[MyClass func] is hooked!");
    gOriginalFunc(self, _cmd);//EXC_BAD_ACCESS occurs here when ARC is enabled!!
}

int main(int argc, char *argv[])
{
    Class clsMyClass = objc_getClass("MyClass");
    // Restore the original method implementation:
    gOriginalFunc = class_getMethodImplementation(clsMyClass, @selector(func));
    Method mtdFunc = class_getInstanceMethod(clsMyClass, @selector(func));
    // Replace implementaion of the method of my own:
    class_replaceMethod(clsMyClass, @selector(func), IMP(HookFunc), method_getTypeEncoding(mtdFunc));
    objc_registerClassPair(clsMyClass);

    MyClass* obj = [[MyClass alloc] init];
    [obj func];

    return 0;
}

但问题发生在启用ARC时(通过将编译器标志设置为-fobjc-ARC)。调用gOriginalFunc时抛出EXC_BAD_访问信号(如注释所示)。我不知道原因,有人能告诉我吗?

您的函数原型不准确,编译器设置的调用不正确。对于ARC,这包括引用计数操作。两者都是未定义的行为

要更正程序,请将实际的函数签名通知编译器,以便它不会破坏调用:

typedef void (*HookFunc_Signature)(id, SEL); // << != IMP's signature
static HookFunc_Signature gOriginalFunc = nil;

注意:objc术语中的“hook”=“swizzling”非常感谢!这很有帮助。虽然我不太清楚为什么返回类型很重要。我发现这个问题发生在目标SDK版本早于7.0的项目上,因为IMP被定义为:typedef id(*IMP)(id,SEL)。它只在返回类型上与HookFunc_签名不同。@user1224028它取决于ABI和ARC(这可能会引入objc差异)。编译器需要知道如何设置函数调用,否则它将读取和/或写入不应该读取和/或写入的内存,并可能以不同的方式对其进行解释。ARC增加了复杂性,因为调用还可能导致编译器引入保留/释放调用。例如,编译器可能会告诉运行时在存储返回值(例如寄存器值)的位置执行引用计数操作。对于void函数,这将是一个垃圾值(=作为对象处理的未定义行为)。我建议您阅读(尤其是第二个脚注)。它神奇地为我修复了这个EXC_坏访问,我能理解为什么!基本上,编译器(和ARC)倾向于保留swizzled方法的结果,当这些方法不返回NSObject实例时,会导致崩溃。正确地强制转换这些函数的结果可以防止编译器保留太多
typedef void (*HookFunc_Signature)(id, SEL); // << != IMP's signature
static HookFunc_Signature gOriginalFunc = nil;
gOriginalFunc = (HookFunc_Signature)class_getMethodImplementation(clsMyClass, @selector(func));