title: IOKit device adding/removal notifications - only fire once?
body: <p>I have been trying to get notified when a specific USB device is added or removed.  I have read 'Accessing Hardware From Applications' document and have a bare-bones demo application, mainly based on the code provided in that document.</p>
  
  <p>It works the first time a device is added or removed, but after that my callbacks never get called.  I cannot work out why?  Can anyone spot where I am going wrong?</p>
  
  <p>(xcode project if you would like to test)
  <a href="http://monkeyfood.com/testIOKitNOtificaiton.zip" rel="noreferrer">http://monkeyfood.com/testIOKitNOtificaiton.zip</a></p>
  
  <p>Thanks.</p>
  
  <pre><code>//
  //  AppDelegate.m
  //  testIOKitNotification
  //
  //  Created by Diggory Laycock on 23/07/2012.
  //  Copyright (c) 2012 MonkeyFood.com. All rights reserved.
  //
  
  #import "AppDelegate.h"
  
  @implementation AppDelegate
  
  
  //          Arduino USB info
  #define     matchVendorID           0x2341      
  #define     matchProductID          0x0043
  
  
  #pragma mark -
  #pragma mark C Callback functions
  #pragma mark -
  
  void usbDeviceAppeared(void *refCon, io_iterator_t iterator){
      NSLog(@"Matching USB device appeared");
  }
  void usbDeviceDisappeared(void *refCon, io_iterator_t iterator){
      NSLog(@"Matching USB device disappeared");
  }
  
  
  @synthesize window = _window;
  
  
  #pragma mark -
  #pragma mark Application Methods
  #pragma mark -
  
  
  
  - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
  {
      io_iterator_t newDevicesIterator;
      io_iterator_t lostDevicesIterator;
  
      newDevicesIterator = 0;
      lostDevicesIterator = 0;
      NSLog(@" ");
  
      NSMutableDictionary *matchingDict = (__bridge NSMutableDictionary *)IOServiceMatching(kIOUSBDeviceClassName);
  
      if (matchingDict == nil){
          NSLog(@"Could not create matching dictionary");
          return;
      }
      [matchingDict setObject:[NSNumber numberWithShort:matchVendorID] forKey:(NSString *)CFSTR(kUSBVendorID)];
      [matchingDict setObject:[NSNumber numberWithShort:matchProductID] forKey:(NSString *)CFSTR(kUSBProductID)];
  
      //  Add notification ports to runloop
      IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
      CFRunLoopSourceRef notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
      CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop], notificationRunLoopSource, kCFRunLoopDefaultMode);
  
      kern_return_t err;
      err = IOServiceAddMatchingNotification(notificationPort, 
                                             kIOMatchedNotification, 
                                             (__bridge CFDictionaryRef)matchingDict, 
                                             usbDeviceAppeared, 
                                             (__bridge void *)self, 
                                             &amp;newDevicesIterator);
      if (err)
      {
          NSLog(@"error adding publish notification");
      }
      [self matchingDevicesAdded: newDevicesIterator];
  
  
      NSMutableDictionary *matchingDictRemoved = (__bridge NSMutableDictionary *)IOServiceMatching(kIOUSBDeviceClassName);
  
      if (matchingDictRemoved == nil){
          NSLog(@"Could not create matching dictionary");
          return;
      }
      [matchingDictRemoved setObject:[NSNumber numberWithShort:matchVendorID] forKey:(NSString *)CFSTR(kUSBVendorID)];
      [matchingDictRemoved setObject:[NSNumber numberWithShort:matchProductID] forKey:(NSString *)CFSTR(kUSBProductID)];
  
  
      err = IOServiceAddMatchingNotification(notificationPort, 
                                             kIOTerminatedNotification, 
                                             (__bridge CFDictionaryRef)matchingDictRemoved, 
                                             usbDeviceDisappeared, 
                                             (__bridge void *)self, 
                                             &amp;lostDevicesIterator);
      if (err)
      {
          NSLog(@"error adding removed notification");
      }
      [self matchingDevicesRemoved: lostDevicesIterator];
  
  
      //      CFRunLoopRun();
      //      [[NSRunLoop currentRunLoop] run];
  
  }
  
  #pragma mark -
  #pragma mark ObjC Callback functions
  #pragma mark -
  
  - (void)matchingDevicesAdded:(io_iterator_t)devices
  {
      io_object_t thisObject;
      while ( (thisObject = IOIteratorNext(devices))) {
          NSLog(@"new Matching device added ");
          IOObjectRelease(thisObject); 
      } 
  
  }
  
  
  - (void)matchingDevicesRemoved:(io_iterator_t)devices
  {
      io_object_t thisObject;
      while ( (thisObject = IOIteratorNext(devices))) {
          NSLog(@"A matching device was removed ");
          IOObjectRelease(thisObject); 
      } 
  
  }
  
  
  @end
  </code></pre>