You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity调用iOS自定义类型方法触发EXC_BAD_ACCESS问题求助

Unity iOS交互传递自定义结构体触发EXC_BAD_ACCESS的原因及解决办法

问题根源

  1. 类型模型不匹配:Unity中LinLoginConfig是值类型结构体,而iOS端定义的是继承自NSObject的Objective-C类——两者内存布局完全不同。Unity传递的是纯值类型的内存块,但iOS端会把它当成带isa指针的Objective-C对象处理,直接导致内存访问越界。
  2. 桥接函数类型错误:iOS桥接函数里的const LinLoginConfig &config引用的是Objective-C类实例,但Unity传入的是C风格结构体的内存数据,类型不匹配引发内存访问错误。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:58:24