I'm trying to unmount a disk in OSX. The code works fine, but the callback is not called when the disk is unmounted successful only when it gives an error. I read the DiskArbitrationProgGuide and followed the steps, but no progress yet. Could someone give me a help?
@interface DriverUtilitiesController()
void unmount_done(DADiskRef disk,
DADissenterRef dissenter,
void *context);
@end
+ (void)umnountDrivePath:(NSString *)voulumePath
{
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
CFURLRef path = CFURLCreateWithString(NULL, (__bridge CFStringRef)voulumePath, NULL);
DADiskRef disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, path);
DADiskUnmount(disk, kDADiskUnmountOptionDefault, unmount_done, NULL);
CFRelease(disk);
}
#pragma mark - Unmount Callback
void unmount_done(DADiskRef disk,
DADissenterRef dissenter,
void *context)
{
NSLog(@"Inside unmount_done");
if (dissenter)
{
// Unmount failed. //
NSLog(@"Unmount failed.");
} else {
NSLog(@"Unmounted Volume");
}
}
Updating. Thanks to Ken Thomases the code now works
- (id)init
{
self = [super init];
self.session = DASessionCreate(kCFAllocatorDefault);
DASessionScheduleWithRunLoop(_session, [[NSRunLoop mainRunLoop] getCFRunLoop], kCFRunLoopDefaultMode);
return self;
}
- (void)umnountDrivePath:(NSString *)voulumePath
{
CFURLRef path = CFURLCreateWithString(NULL, (__bridge CFStringRef)voulumePath, NULL);
DADiskRef disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, self.session, path);
DADiskUnmount(disk, kDADiskUnmountOptionDefault, unmount_done, (__bridge void *)(self));
CFRelease(disk);
}
void unmount_done(DADiskRef disk,
DADissenterRef dissenter,
void *context)
{
if (dissenter)
{
// Unmount failed. //
NSLog(@"Unmount failed.");
} else {
NSLog(@"Unmounted Volume");
}
DriverUtilitiesController *driverUtilitiesController = (__bridge DriverUtilitiesController *)context;
[driverUtilitiesController clearUnmountCallback];
}
- (void)clearUnmountCallback
{
DASessionUnscheduleFromRunLoop(_session, [[NSRunLoop mainRunLoop] getCFRunLoop], kCFRunLoopDefaultMode);
CFRelease(self.session);
}
DADiskUnmount()
operates asynchronously. The disk has not necessarily been unmounted by the time the function returns to your code. If it succeeds, it may happen at some later time. Your callback will be called at that time.
The mechanism by which a program waits for that event and calls your callback in response is either a run loop or a dispatch queue. The session object is responsible for managing this waiting and calling. You need to schedule the session object on a run loop or dispatch queue. You use either DASessionScheduleWithRunLoop()
or DASessionSetDispatchQueue()
, as described in Disk Arbitration Programming Guide: Using Disk Arbitration Notification and Approval Callbacks – Scheduling the Session with the Run Loop or Dispatch Queue.
That means that you don't want to create a new session object for every attempt to unmount a disk. Also, you want to keep a reference to the session object so that you can unschedule and release it when you no longer need it (which would be sometime after you no longer need to get callbacks from it).