objective-c - 内存泄漏 - 不确定如何/在哪里 CFRelease() CFSet
问题描述
我再次为内存泄漏而苦苦挣扎,需要一些帮助来解决这个问题。我知道(或很确定)CFSet 是这里的问题。
我假设我需要对它们进行 CFRelease(),但我不确定如何实现这一点,因为我还需要在 USBDeviceCount() 中返回一个 CFSet。任何帮助,将不胜感激!谢谢!
这是代码(看起来效果很好!除了泄漏):
// New USB device has been added (callback function)
static void Handle_DeviceMatchingCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDDeviceRef inIOHIDDeviceRef){
// Log the device ID & device count
NSLog(@"\nNew USB device: %p\nDevice count: %ld",
(void *)inIOHIDDeviceRef,
USBDeviceCount(inSender));
}
// USB device has been removed (callback function)
static void Handle_DeviceRemovalCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDDeviceRef inIOHIDDeviceRef){
// Log the device ID & device count
NSLog(@"\nUSB device removed: %p\nDevice count: %ld",
(void *)inIOHIDDeviceRef,
USBDeviceCount(inSender));
}
// Counts the number of devices in the device set (includes all USB devices that match dictionary)
static long USBDeviceCount(IOHIDManagerRef HIDManager)
{
// The device set includes all USB devices that match our matching dictionary. Fetch it.
CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager);
// The devSet will be NULL if there are 0 devices, so only try to count the devices if devSet exists
if(devSet) return CFSetGetCount(devSet);
// There were no matching devices (devSet was NULL), so return a count of 0
return 0;
}
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification {
// Create an HID Manager
IOHIDManagerRef HIDManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
// Create a Matching Dictionary
CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(
kCFAllocatorDefault,
2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Specify a device manufacturer in the Matching Dictionary
CFDictionarySetValue(matchDict,
CFSTR(kIOHIDTransportKey),
CFSTR("USB"));
// Register the Matching Dictionary to the HID Manager
IOHIDManagerSetDeviceMatching(HIDManager, matchDict);
// Register a callback for USB device detection with the HID Manager
IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &Handle_DeviceMatchingCallback, NULL);
// Register a callback fro USB device removal with the HID Manager
IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, &Handle_DeviceRemovalCallback, NULL);
// Register the HID Manager on our app’s run loop
IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
// Open the HID Manager
IOReturn IOReturn = IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone);
if(IOReturn) NSLog(@"IOHIDManagerOpen failed."); // Couldn't open the HID manager!
CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager);
CFRelease(devSet);
CFRelease(matchDict);
}
为了完整起见,这是我在卡尔的帮助下能够实施的解决方案(谢谢,卡尔!!):
AppDelegate.h:
- (void) updateConnectedUSBs;
@property(retain) __attribute__((NSObject)) IOHIDManagerRef hidManager;
@property (strong) NSSet *usbDeviceSet;
AppDelegate.m:
// New USB device has been added (callback function)
static void Handle_DeviceMatchingCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDDeviceRef inIOHIDDeviceRef){
AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
[appDelegate updateConnectedUSBs];
}
// USB device has been removed (callback function)
static void Handle_DeviceRemovalCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDDeviceRef inIOHIDDeviceRef){
AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
[appDelegate updateConnectedUSBs];
}
- (void) updateConnectedUSBs {
CFSetRef devSet = IOHIDManagerCopyDevices(_hidManager);
self.usbDeviceSet = CFBridgingRelease(devSet);
NSLog(@"%@",self.usbDeviceSet);
}
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
// Create a Matching Dictionary
CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(
kCFAllocatorDefault,
2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Specify a device manufacturer in the Matching Dictionary
CFDictionarySetValue(matchDict,
CFSTR(kIOHIDTransportKey),
CFSTR("USB"));
// Register the Matching Dictionary to the HID Manager
IOHIDManagerSetDeviceMatching(_hidManager, matchDict);
// Register a callback for USB device detection with the HID Manager
IOHIDManagerRegisterDeviceMatchingCallback(_hidManager, &Handle_DeviceMatchingCallback, NULL);
// Register a callback fro USB device removal with the HID Manager
IOHIDManagerRegisterDeviceRemovalCallback(_hidManager, &Handle_DeviceRemovalCallback, NULL);
// Register the HID Manager on our app’s run loop
IOHIDManagerScheduleWithRunLoop(_hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
// Open the HID Manager
IOReturn IOReturn = IOHIDManagerOpen(_hidManager, kIOHIDOptionsTypeNone);
if(IOReturn) NSLog(@"IOHIDManagerOpen failed."); // Couldn't open the HID manager!
CFRelease(matchDict);
}
解决方案
您需要在释放集合之前存储计数。(这是所有 NSObject 子类在 ARC 之前通过 -release 方法工作的方式。)
if (devSet) {
long count = (long)CFSetGetCount(devSet);
CFRelease(devSet);
return count;
}
如果你可以使用 CFAutorelease() 函数,这是另一种你可以在创建后立即调用的方法,它将在运行循环结束时被收集。但是如果不给代码增加任何复杂性,直接使用 CFRelease 会更有效一些。如果有多个退货,提前自动释放有时可以避免以后进行多次检查。
我相信,您还需要 CFRelease HIDManager 实例。
推荐阅读
- angular - Angular8/TypeScript:map.set() 不是函数
- google-drive-api - tFileOutputDelimited 输出流到 tGoogleDrivePut
- python - 如何避免在 React Native 中轮询服务器以获取新数据?
- nginx - Nginx 配置将一系列端口绑定到 80 并将 proxy_pass 设置为数字路由
- javascript - 在 div 内拖动元素,但拖动时元素闪烁
- r - 使用 Merge.xts 函数将多个 xts 文件合并在一起
- ethereum - 如何使用本地主机测试 Dai
- c# - 如何从麦克斯韦分布中绘制直方图?
- java - TrueTime Sometimes not giving value
- javascript - 如果用户在 iframe 中通过身份验证而不是重定向父窗口,则 iframe