使用objc_msgSend_fpret()获取cpm属性返回NaN,控制台可见值却无法获取求助
问题分析与解决建议
Hey,刚好之前也踩过objc_msgSend系列函数的坑,来给你拆解下可能的原因和解决办法:
可能的问题根源
- 类型不匹配:
objc_msgSend_fpret是专门用来处理返回浮点基本类型(比如float、double)的消息发送,但如果你的cpm属性是NSNumber这类包装对象,直接用它就会因为类型解析错误返回NaN——毕竟它没法把对象指针解析成浮点数。 - 调用约定或声明缺失:如果没有提前正确声明
objc_msgSend_fpret的函数原型,编译器可能会错误处理返回值的传递逻辑(浮点返回值在部分架构下是通过专门的浮点寄存器传递的),导致拿到无效的NaN值。 - SEL与实际getter不匹配:如果
cpm属性有自定义getter方法(比如不是默认的-cpm),传错SEL也会导致调用失败,返回无意义的结果。
解决步骤
先确认
cpm的实际类型
先通过类的头文件或者runtime工具确认属性类型:- 如果是浮点基本类型(float/double):确保正确声明函数原型后再调用:
注意:如果是float类型,可将返回值强转为float,适配对应类型。#import <objc/message.h> // 提前声明函数原型,避免编译器报错 extern double objc_msgSend_fpret(id self, SEL _cmd, ...); // 调用示例 double cpmValue = objc_msgSend_fpret(yourTargetObject, @selector(cpm)); - 如果是NSNumber对象:不能用
objc_msgSend_fpret,改用普通objc_msgSend获取对象再取值:NSNumber *cpmObj = ((NSNumber *(*)(id, SEL))objc_msgSend)(yourTargetObject, @selector(cpm)); double cpmValue = [cpmObj doubleValue];
- 如果是浮点基本类型(float/double):确保正确声明函数原型后再调用:
验证调用的SEL正确性
打印属性的编码信息,确认getter方法名和你传入的SEL一致:objc_property_t property = class_getProperty([yourTargetObject class], "cpm"); const char *attrs = property_getAttributes(property); NSLog(@"Property attributes: %s", attrs);比如编码里的
G,cpm就表示getter是cpm,确保SEL和它完全对应。用runtime动态适配类型(可选)
如果不确定属性类型,可以通过属性编码动态选择调用的msgSend函数:objc_property_t property = class_getProperty([yourTargetObject class], "cpm"); const char *attrs = property_getAttributes(property); NSString *attrStr = [NSString stringWithUTF8String:attrs]; if ([attrStr containsString:@"f"] || [attrStr containsString:@"d"]) { // 浮点类型,用objc_msgSend_fpret double value = objc_msgSend_fpret(yourTargetObject, @selector(cpm)); NSLog(@"cpm value: %f", value); } else if ([attrStr containsString:@"@"]) { // 对象类型,用objc_msgSend id valueObj = ((id (*)(id, SEL))objc_msgSend)(yourTargetObject, @selector(cpm)); NSLog(@"cpm value: %@", valueObj); }
额外提示
控制台能看到属性值,说明属性本身是有正确赋值的,问题大概率出在objc_msgSend_fpret的使用场景和属性类型不匹配上,先从类型验证入手应该就能解决~
内容的提问来源于stack exchange,提问作者Zhaoxiangyulove
相关产品推荐
相关产品推荐

