iOS14.6下@objc枚举存入字典触发malloc分配崩溃问题求助
问题原因分析
这是iOS 14.6系统中Swift与Objective-C桥接的特定bug导致的:你定义的ConnectState是标记@objc的UInt8类型枚举,当把它的rawValue(UInt8类型)或枚举本身存入[String: Any]字典时,Swift在将UInt8桥接为Objective-C兼容的NSNumber时出现错误,错误地将极小的UInt8值解析成了超大的内存分配尺寸(日志里的1152921504606863360是典型的64位溢出后的值),最终触发malloc分配失败。
而直接将枚举作为userInfo参数传入NotificationCenter时,系统使用了更直接的Swift类型传递路径,绕过了有问题的桥接逻辑,因此未出现崩溃。
解决方法
以下方案按推荐程度排序:
方案1:将UInt8 rawValue转换为Int后存入字典
修改赋值代码,把connectState.rawValue转为Int类型,避免桥接时的类型错误:
func connectStateChange(_ connectState: ConnectState, _ serialNumber: String) { var userInfo: [String: Any] = [:] // 转换为Int后存入字典 userInfo[ConstValue.connectState] = Int(connectState.rawValue) userInfo[ConstValue.serialNumber] = serialNumber NotificationCenter.default.post(name: Notification.Name(Global.HomeDeviceStateChange), object: nil, userInfo: userInfo) }
接收通知时,再将Int转回UInt8初始化枚举:
// 通知接收代码示例 if let stateRawValue = userInfo[ConstValue.connectState] as? Int, let connectState = ConnectState(rawValue: UInt8(stateRawValue)) { // 使用connectState进行业务逻辑处理 }
方案2:修改枚举的原始值类型为UInt/Int
直接将枚举的原始值类型从UInt8改为UInt或Int,规避iOS14.6的桥接bug:
@objc enum ConnectState: UInt { // 也可使用Int类型 case connected = 0x00 case disConnected = 0x01 // 保留原有的description实现 }
修改后原赋值代码无需改动,可直接存入字典:
// 存rawValue或枚举本身都可以 userInfo[ConstValue.connectState] = connectState.rawValue // 或者 userInfo[ConstValue.connectState] = connectState
方案3:自定义包装结构体(备选方案)
如果不想修改枚举或rawValue类型,可以用简单结构体包装枚举,避免直接桥接UInt8:
struct ConnectStateWrapper { let state: ConnectState }
存入字典时:
userInfo[ConstValue.connectState] = ConnectStateWrapper(state: connectState)
接收通知时取出包装器获取枚举值即可。
内容的提问来源于stack exchange,提问作者Avicii4ever
相关产品推荐
相关产品推荐

