首次使用Objective-C Runtime调用UTF8String崩溃原因咨询
咱们直接戳中问题核心:你的崩溃完全是因为对UTF8String的返回值错误使用了CFBridgingRetain,NSString类簇只是表象,本质是返回值类型不匹配导致的非法内存操作。
具体拆解问题:
UTF8String的返回值本质NSString的UTF8String方法返回的是const char *——这是一个指向字符串内部缓冲区的原始C指针,它既不是Objective-C对象,也不是符合Core Foundation内存管理规则的CFTypeRef类型,没有CF对象必备的头部元数据(比如保留计数字段)。CFBridgingRetain的适用场景
这个宏的作用是把合法的Core Foundation对象(CFTypeRef)转换成Objective-C对象,同时对其执行CFRetain操作(等价于OC的retain)。它要求输入必须是带有CF对象结构的指针,否则会触发非法内存访问。崩溃的直接触发点
当调用myMsgSend(description, "UTF8String")时,methodIMP(receiver, selector)返回的是const char *指针。你把这个指针传给CFBridgingRetain,宏会错误地将其当作CFTypeRef执行CFRetain操作,直接访问了不属于这个指针的内存区域,最终导致崩溃。
为什么init和description能正常工作?
因为这两个方法的返回值都是id(Objective-C对象),而OC对象在Core Foundation层面可以和对应的CF对象互转(比如NSString对应CFStringRef),所以CFBridgingRetain能正确识别对象结构并执行retain操作,自然不会出问题。
修复方案:根据返回值类型做差异化处理
你不能一概而论用CFBridgingRetain处理所有方法的返回值,需要先判断返回值类型再做对应操作:
static const void *myMsgSend(id receiver, const char *name) { SEL selector = sel_registerName(name); Class receiverClass = object_getClass(receiver); Method method = class_getInstanceMethod(receiverClass, selector); if (!method) { return NULL; } // 获取返回值类型编码 char returnType[16]; method_getReturnType(method, returnType, sizeof(returnType)); IMP methodIMP = class_getMethodImplementation(receiverClass, selector); if (strcmp(returnType, "@") == 0) { // 返回对象类型,用CFBridgingRetain处理 id result = methodIMP(receiver, selector); return CFBridgingRetain(result); } else if (strcmp(returnType, "*") == 0) { // 返回const char *,直接返回原始指针 return methodIMP(receiver, selector); } // 其他基础类型(如int、float等)可按需扩展处理逻辑 return NULL; }
这样修改后,调用UTF8String时就不会执行错误的CFBridgingRetain操作,崩溃问题就能解决。
内容的提问来源于stack exchange,提问作者Rohan Bhale

