Swift中使用CFDictionarySetValue导致崩溃问题求助
问题描述
开发基于Swift的macOS应用,使用IOKit获取USB设备信息时,调用CFDictionarySetValue触发崩溃,报错信息:
Thread 1: EXC_BAD_ACCESS (code=1,...)
原代码如下:
var matchingDict: CFMutableDictionary? var val: NSNumber.IntegerLiteralType var valRef: CFNumber? matchingDict = IOServiceMatching(kIOHIDDeviceKey) if let matchingDict { val = 1917 valRef = CFNumberCreate(kCFAllocatorDefault, CFNumberType.sInt32Type, UnsafeMutableRawPointer?(&val)) CFDictionarySetValue(matchingDict, UnsafeRawPointer?(kIOHIDVendorIDKey), unsafeBitCast(valRef, to: UnsafeRawPointer.self)) }
尝试过三种写法均存在问题:
第一种写法(有警告,运行时崩溃):
valRef = CFNumberCreate(kCFAllocatorDefault, .sInt32Type, UnsafeMutableRawPointer?(&val))警告信息:
Forming 'UnsafeRawPointer' to a variable of type 'Optional'; this is likely incorrect because 'Optional' may contain an object reference.
第二种写法(编译通过但崩溃):
CFDictionarySetValue(matchingDict, unsafeBitCast(kIOHIDVendorIDKey, to: UnsafeRawPointer.self), unsafeBitCast(valRef, to: UnsafeRawPointer.self))第三种写法(依旧崩溃):
CFDictionarySetValue(matchingDict, UnsafeRawPointer?(kIOHIDVendorIDKey), unsafeBitCast(valRef, to: UnsafeRawPointer.self))
错误原因与修正
崩溃的核心问题有两点:
CFNumberCreate指针传递错误:你传递了&val的可选指针包装,而CFNumberCreate需要指向数值的非可选原始指针;同时NSNumber.IntegerLiteralType本质是Int,和你指定的sInt32Type类型不匹配,直接导致内存访问异常。- CFDictionary键值类型转换错误:
kIOHIDVendorIDKey本身就是CFString类型,无需强制转成UnsafeRawPointer;valRef是合法的CFNumber对象,直接传递即可——unsafeBitCast会破坏CF对象的内存管理规则,引发野指针访问。
修正后的代码
var matchingDict: CFMutableDictionary? // 用Int32类型匹配CFNumber的sInt32Type let vendorID: Int32 = 1917 var valRef: CFNumber? matchingDict = IOServiceMatching(kIOHIDDeviceKey) if let matchingDict { // 传递非可选的指针,直接取vendorID的内存地址 valRef = CFNumberCreate(kCFAllocatorDefault, .sInt32Type, &vendorID) // 直接传入CFString和CFNumber对象,无需unsafeBitCast CFDictionarySetValue(matchingDict, kIOHIDVendorIDKey, valRef) }
更简洁的Swift化写法
利用Core Foundation与Foundation的toll-free bridging特性,完全避免手动管理CF指针的麻烦:
if let matchingDict = IOServiceMatching(kIOHIDDeviceKey) as? NSMutableDictionary { let vendorID: Int32 = 1917 matchingDict[kIOHIDVendorIDKey] = vendorID }
内容的提问来源于stack exchange,提问作者Karterilla
相关产品推荐
相关产品推荐

