Unity调用iOS自定义类型方法触发EXC_BAD_ACCESS问题求助
Unity iOS交互传递自定义结构体触发EXC_BAD_ACCESS的原因及解决办法
问题根源
- 类型模型不匹配:Unity中
LinLoginConfig是值类型结构体,而iOS端定义的是继承自NSObject的Objective-C类——两者内存布局完全不同。Unity传递的是纯值类型的内存块,但iOS端会把它当成带isa指针的Objective-C对象处理,直接导致内存访问越界。 - 桥接函数类型错误:iOS桥接函数里的
const LinLoginConfig &config引用的是Objective-C类实例,但Unity传入的是C风格结构体的内存数据,类型不匹配引发内存访问错误。 - NSLog格式化符误用:代码中用
%@打印&config,%@是Objective-C对象的格式化符,系统会尝试读取该地址的isa指针(Objective-C对象的首字段),但这里的地址是结构体内存,自然触发EXC_BAD_ACCESS。
解决方案
方案一:统一使用C/C++结构体(推荐)
保证两端类型的内存布局完全一致,用纯C/C++结构体实现跨语言传递:
- Unity端结构体定义保持不变:
[Serializable] public struct LinLoginConfig { public bool haveEmail; } [DllImport("__Internal")] private static extern void saveLoginConfig(ref LinLoginConfig config); // 调用示例 saveLoginConfig(ref config);
- iOS端在Objective-C++文件(.mm后缀)中定义匹配的C结构体,并用
extern "C"避免函数名混淆:
extern "C" { typedef struct { bool haveEmail; } LinLoginConfig; void saveLoginConfig(const LinLoginConfig *config) { // 用%hhd打印bool类型,避免格式化符不匹配问题 NSLog(@"saveLoginConfig haveEmail: %hhd", config->haveEmail); } }
方案二:序列化后传递(适合复杂类型)
如果需要在iOS端使用Objective-C对象,可以将Unity的结构体序列化为JSON或二进制数据,传递后再解析:
- Unity端序列化:
string json = JsonUtility.ToJson(config); saveLoginConfig(json); [DllImport("__Internal")] private static extern void saveLoginConfig(string jsonStr);
- iOS端解析:
extern "C" void saveLoginConfig(const char* jsonStr) { NSString *jsonString = [NSString stringWithUTF8String:jsonStr]; NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSError *error = nil; NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; if (!error) { BOOL haveEmail = [configDict[@"haveEmail"] boolValue]; NSLog(@"saveLoginConfig haveEmail: %d", haveEmail); } }
方案三:使用你发现的Objective-C++类方案
你提到的在Objective-C中声明C类的方案可行,核心是C类的内存布局可以和Unity的结构体对齐(只要成员顺序、类型完全一致),同时extern "C"保证了函数调用的ABI兼容性。注意保持C类和Unity结构体的成员一一对应,避免内存偏移问题:
extern "C" { class LinLoginConfig { public: bool haveEmail; // 其他成员需和Unity结构体完全匹配 }; void saveLoginConfig(const LinLoginConfig &config) { NSLog(@"saveLoginConfig haveEmail: %hhd", config.haveEmail); } }
核心注意事项
- 跨语言传递自定义类型时,两端内存布局必须完全一致,包括成员顺序、类型大小、内存对齐规则。
- 禁止混用Objective-C对象和C/C++值类型作为跨语言参数——Objective-C对象包含isa指针等额外内存结构,无法和值类型兼容。
- NSLog格式化符必须和参数类型匹配:
%hhd对应bool,%d对应int,%@仅用于Objective-C对象。
内容的提问来源于stack exchange,提问作者Fan Applelin
相关产品推荐
相关产品推荐

