简体   繁体   中英

Disk Arbitration and OK button issue

The code below is used to get the list of disks

(void)da_tools
{
    DASessionRef session;

    session = DASessionCreate(kCFAllocatorDefault);
    DARegisterDiskAppearedCallback(session, NULL, disk_appeared_callback, (void *)NULL);
    DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    CFRunLoopRun();
    CFRelease(session);
}

The IBAction for the OK button is: [self da_tools] ;

The callback function disk_appeared_callback works perfectly and give the right information.

The problem happens at CFRunLoopRun() when the OK button is hit:

  • the CFRunLoopRun() take many seconds to execute or never end.
  • The callback function disk_appeared_callback itself is executed in milli-seconds time.

However any key press to the keyboard (or a mouse click everywhere (and sometime just a mouse move)) force CFRunLoopRun() to exit and the callback function disk_appeared_callback is promptly executed.

When CFRunLoopRun() is removed da_tools does not return any disk information at the first OK button hit but subsequent OK button hit returns the correct disk information.

I have tried to include da_tools in an another thread:

[NSThread detachNewThreadSelector:@selector(da_tools) toTarget:self withObject:nil]

but this doesn't help.

I also tried to post a keydown event but this fails too.

How to use CFRunLoopRun correctly?

Please do not to use call CFRunLoopRun(); method separately and please not release session CFRelease(session); because you will not received any callback later on.


How to established session with DiskArbitration and listen via callbacks?

Creating DA session and schedule session run loop:

// Disk Arbitration Session
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
if (!session) {
    [NSException raise:NSGenericException format:@"Unable to create Disk Arbitration session."];
    return;
}

NSLog(@"Disk Arbitration Session created");

// schedule DA session run loop
DASessionScheduleWithRunLoop(session, CFRunLoopGetMain(), kCFRunLoopCommonModes);

If you like to listen for all disk events including internal one. Then Pass NULL while registering callbacks.

Else create a matching condition for your callbacks. For example: following condition for external hard disk, memory disk connects via USB.

// Matching Conditions
CFMutableDictionaryRef match = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

// Device matching criteria
// 1. Of-course it shouldn't be internal device since
CFDictionaryAddValue(match, kDADiskDescriptionDeviceInternalKey, kCFBooleanFalse);

// Volume matching criteria
// It should statisfy following
CFDictionaryAddValue(match, kDADiskDescriptionVolumeMountableKey, kCFBooleanTrue);
CFDictionaryAddValue(match, kDADiskDescriptionVolumeNetworkKey, kCFBooleanFalse);

Look at DADisk.h , we add more conditions for your need.

Registering Callbacks with DiskArbitration, more info on callbacks here -

NSString * const AppName = @"DAApp";

// Registring callbacks
DARegisterDiskAppearedCallback(session, match, DiskAppearedCallback, (__bridge void *)AppName);
DARegisterDiskDisappearedCallback(session, match, DiskDisappearedCallback, (__bridge void *)AppName);
DARegisterDiskDescriptionChangedCallback(session, match, NULL, DiskDescriptionChangedCallback, (__bridge void *)AppName);

// And now release match
CFRelease(match);

... Application things goes around...**

Finally Unregister and release everything. Typical place is application terminate or dealloc.

// DA Session
if (session) {
    DAUnregisterCallback(session, DiskAppearedCallback, (__bridge void *)AppName);
    DAUnregisterCallback(session, DiskDisappearedCallback, (__bridge void *)AppName);

    DASessionUnscheduleFromRunLoop(session, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    CFRelease(session);

    NSLog(@"Disk Arbitration Session destoryed");
}

I hope it helps!


BTW, for DA Approval Session like this

// Disk Arbitration Approval Session
DASessionRef approvalSession = DAApprovalSessionCreate(kCFAllocatorDefault);
if (!approvalSession) {
    NSLog(@"Unable to create Disk Arbitration approval session.");
    return;
}

NSLog(@"Disk Arbitration Approval Session created");
DAApprovalSessionScheduleWithRunLoop(approvalSession, CFRunLoopGetMain(), kCFRunLoopCommonModes);

// Same match condition for Approval session too
DARegisterDiskMountApprovalCallback(approvalSession, match, DiskMountApprovalCallback, (__bridge void *)AppName);

// may need CFRelease(match); based code sequence!

Finally unregister and release.

// DA Approval Session
if (approvalSession) {
    DAUnregisterApprovalCallback(approvalSession, DiskMountApprovalCallback, (__bridge void *)AppName);

    DAApprovalSessionUnscheduleFromRunLoop(approvalSession, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    CFRelease(approvalSession);

    NSLog(@"Disk Arbitration Approval Session destoryed");
}

For more info on above code snippets here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM