内存泄漏 - 不确定 How/Where 到 CFRelease() CFSet

Memory Leak - Not Sure How/Where to CFRelease() CFSet

我又一次与内存泄漏作斗争,需要一些帮助来解决这个问题。我知道(或者非常确定)CFSet(s) 是这里的问题。

我假设我需要 CFRelease() 它们,但我不确定如何完成此操作,因为我还需要 return 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);

}

为了完整起见,这是我在 Carl 的帮助下实现的解决方案(感谢 Carl!!):

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 会更有效一些。如果有多个 returns.

,提前自动释放有时可以避免以后的多次检查

我相信您还需要 CFRelease HIDManager 实例。