14

I have an OS X application that needs to respond to a volume being mounted or unmounted.

I've already solved this problem by retrieving the list of volumes periodically and checking for changes, but I'd like to know if there is a better way.

Brian
  • 6,910
  • 8
  • 44
  • 82

4 Answers4

17

Register to the notification center you get from [[NSWorkspace sharedWorkspace] notificationCenter] and then process the notifications you are interested in. These are the volume related ones: NSWorkspaceDidRenameVolumeNotification, NSWorkspaceDidMountNotification, NSWorkspaceWillUnmountNotification and NSWorkspaceDidUnmountNotification.

Analog File
  • 5,280
  • 20
  • 23
16

The NSWorkspace approach is exactly the kind of thing I was looking for. A few lines of code later, I have a much better solution than using a timer.

-(void) monitorVolumes
{
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumesChanged:) name:NSWorkspaceDidMountNotification object: nil];
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector: @selector(volumesChanged:) name:NSWorkspaceDidUnmountNotification object:nil];
}

-(void) volumesChanged: (NSNotification*) notification
{
    NSLog(@"dostuff");
}
Brian
  • 6,910
  • 8
  • 44
  • 82
6

Swift 4 version:

Declare NSWorkspace in applicationDidFinishLaunching and add observers for mount and unmount events.

let workspace = NSWorkspace.shared

workspace.notificationCenter.addObserver(self, selector: #selector(didMount(_:)), name: NSWorkspace.didMountNotification, object: nil)
workspace.notificationCenter.addObserver(self, selector: #selector(didUnMount(_:)), name: NSWorkspace.didUnmountNotification, object: nil)

Capture mount and unmount events in:

@objc func didMount(_ notification: NSNotification)  {
    if let devicePath = notification.userInfo!["NSDevicePath"] as? String {
        print(devicePath)
    }
}
@objc func didUnMount(_ notification: NSNotification)  {
    if let devicePath = notification.userInfo!["NSDevicePath"] as? String {
        print(devicePath)
    }
}

It will print device path e.g /Volumes/EOS_DIGITAL Here are the constants you can read from userInfo.

NSDevicePath, 
NSWorkspaceVolumeLocalizedNameKey
NSWorkspaceVolumeURLKey
modusCell
  • 13,151
  • 9
  • 53
  • 80
3

Do you know SCEvents? It allows you to be notified when the contents of an observed folder change (/Volumes). This way you don't have to use a timer to periodically check the contents.

DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • Is there a reason to use this over NSWorkspace as described below? It's a 3rd party library, so the benefits would have to be significant in order to convince me to add an additional dependency to the project. – Brian Sep 13 '12 at 15:51