繁体   English   中英

Objective-C运行时崩溃

[英]Objective-C runtime crash

我第一次尝试使用Objective-C运行时方法。 我一直在阅读iOS 7编程中有关这一极限的一章(24)。 按照本书中的示例,我实现了一个消息分发器功能,如下所示:

static const void *myMsgSend(id receiver, const char *name) {
    SEL selector = sel_registerName(name);
    Class receiverClass = object_getClass(receiver);
    IMP methodIMP = class_getMethodImplementation(receiverClass, selector);
    return CFBridgingRetain(methodIMP(receiver, selector));
}

我在以下函数中测试此调度程序:

void runMyMsgSend() {
    // NSObject *object = [[NSObject alloc] init];
    Class class = (Class)objc_getClass("NSObject");
    id object = class_createInstance(class, 0);
    myMsgSend(object, "init");

    // id description = [object description];
    id description = (__bridge id)myMsgSend(object, "description");

    // const char *cstr = [description UTF8String];
    const char *cstr = myMsgSend(description, "UTF8String");

    printf("---------------------");
    printf("%s\n", cstr);
}

该函数对于NSObject类型的对象实例的初始化描述非常有效。 在以UTF8String作为运行方法的描述指向的对象上调用分派器函数时,它崩溃

返回CFBridgingRetain(methodIMP(receiver,selector));

现在我知道NSString是一个群集,实际上使用了__NSCFString的对象。 我认为这可能是调用CFBridgingRetain时出现的问题。 我需要更好地了解真正导致崩溃的原因。 提前致谢。

您正在尝试在所有返回类型上调用CFBridgingRetain

该文档明确指出,如果IMP返回的结果不是NOT void ,则必须将其明确转换为正确的函数指针类型。

您的功能是:

static const void *myMsgSend(id receiver, const char *name) {
    SEL selector = sel_registerName(name);
    Class receiverClass = object_getClass(receiver);
    IMP methodIMP = class_getMethodImplementation(receiverClass, selector);
    id (*imp)(id, SEL) = (id (*)(id, SEL))methodIMP;
    return CFBridgingRetain(imp(receiver, selector));
}

当您调用UTF8String ,它将返回您尝试保留的const char* 不仅如此,您还说IMP返回一个id然后保留该id 。您只能保留Objective-C类对象。 您从未转换为正确的函数指针类型,因此尝试将const char*隐式转换为id时崩溃。

因此,您的方法需要为:

static const void *myMsgSend(id receiver, const char *name) {
    SEL selector = sel_registerName(name);
    Class receiverClass = object_getClass(receiver);
    IMP methodIMP = class_getMethodImplementation(receiverClass, selector);

    void* (*imp)(id, SEL) = (void* (*)(id, SEL))methodIMP;
    return imp(receiver, selector, args);
}

返回简单的void* ,该值可以为NULL或BOOL或int或w / e类型(原始)。如果需要返回对象,则该对象被隐式桥接,因此无需保留(只需将结果强制转换为正确的类型)。

但是,使用NSInvocation作为此函数的实现可能是一个更好的主意,因为这样您就不必担心类型和参数等等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM