Objective-C 运行时崩溃
Objective-C runtime crash
我第一次尝试 Objective-C 运行时间方法。我一直在阅读 iOS 7 programming pushing the limits 中关于此的章节 (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);
}
该函数适用于 init 和 description 类型 NSObject 的对象实例。
当在 description 指向的对象上调用调度程序函数并使用 UTF8String 作为 运行 的方法时,它会在
上崩溃
return CFBridgingRetain(methodIMP(receiver, selector));
现在我知道NSString是一个簇,实际上使用了__NSCFString的一个对象。我认为这可能是调用 CFBridgingRetain 时的问题。我需要更好地了解真正导致崩溃的原因。提前致谢。
您正在尝试对所有 return 类型调用 CFBridgingRetain
..
文档明确指出,如果 IMP
return 不是 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
时,它 return 是您试图保留的 const char*
。不仅如此,你还说 IMP
return 是一个 id
并且你保留了那个。你只能保留 Objective-C class 个对象。您从未强制转换为正确的函数指针类型,因此它在尝试将 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);
}
其中 return 是一个简单的 void*
,它可以是 NULL 或 BOOL 或 int 或 w/e 类型(原始类型)。如果它需要 return 一个对象,对象被隐式桥接,因此无需保留(只需将结果转换为正确的类型)。
但是,使用 NSInvocation
作为此函数的实现可能是一个更好的主意,因为这样您就不必担心类型和参数等问题..
我第一次尝试 Objective-C 运行时间方法。我一直在阅读 iOS 7 programming pushing the limits 中关于此的章节 (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);
}
该函数适用于 init 和 description 类型 NSObject 的对象实例。 当在 description 指向的对象上调用调度程序函数并使用 UTF8String 作为 运行 的方法时,它会在
上崩溃return CFBridgingRetain(methodIMP(receiver, selector));
现在我知道NSString是一个簇,实际上使用了__NSCFString的一个对象。我认为这可能是调用 CFBridgingRetain 时的问题。我需要更好地了解真正导致崩溃的原因。提前致谢。
您正在尝试对所有 return 类型调用 CFBridgingRetain
..
文档明确指出,如果 IMP
return 不是 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
时,它 return 是您试图保留的 const char*
。不仅如此,你还说 IMP
return 是一个 id
并且你保留了那个。你只能保留 Objective-C class 个对象。您从未强制转换为正确的函数指针类型,因此它在尝试将 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);
}
其中 return 是一个简单的 void*
,它可以是 NULL 或 BOOL 或 int 或 w/e 类型(原始类型)。如果它需要 return 一个对象,对象被隐式桥接,因此无需保留(只需将结果转换为正确的类型)。
但是,使用 NSInvocation
作为此函数的实现可能是一个更好的主意,因为这样您就不必担心类型和参数等问题..