macos - 磁盘仲裁和“确定”按钮问题

标签 macos cocoa diskarbitration

下面的代码用于获取磁盘列表

(void)da_tools
{
    DASessionRef session;

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

“确定”按钮的 IBAction 为:[self da_tools];

回调函数disk_appeared_callback工作完美并提供正确的信息。

当点击“确定”按钮时,问题发生在CFRunLoopRun()处:

  • CFRunLoopRun()需要很多秒才能执行或永远不会结束。
  • 回调函数disk_appeared_callback本身以毫秒为单位执行。

但是,按下键盘上的任意键(或到处单击鼠标(有时只需移动鼠标)) 强制CFRunLoopRun()退出,并立即执行回调函数disk_appeared_callback

CFRunLoopRun()被删除时,da_tools在第一次点击“确定”按钮时不会返回任何磁盘信息 但随后点击“确定”按钮会返回正确的磁盘信息。

我尝试在另一个线程中包含 da_tools:

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

但这没有帮助。

我还尝试发布 keydown 事件,但这也失败了。

如何正确使用CFRunLoopRun

最佳答案

请不要单独使用call CFRunLoopRun();方法,也不要释放 session CFRelease(session);,因为稍后您将不会收到任何回调。

<小时/>

如何与 DiskArbitration 建立 session 并通过回调监听?

创建 DA session 并安排 session 运行循环:

// 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);

如果您想监听所有磁盘事件,包括内部事件。然后在注册回调时传递NULL

否则为您的回调创建一个匹配条件。例如:以下情况为外接硬盘,存储盘通过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);

看看DADisk.h,我们根据您的需要添加了更多条件。

使用 DiskArbitration 注册回调,有关回调的更多信息 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);

...应用程序的事情发生...**

最后取消注册并释放所有内容。典型的地方是应用程序终止或释放。

// 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");
}

希望对您有帮助!

<小时/>

顺便说一句,对于这样的 DA 批准 session

// 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!

最终注销并发布。

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

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

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

有关上述代码片段的更多信息 here .

关于macos - 磁盘仲裁和“确定”按钮问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25242752/

相关文章:

macos - 如何使用 Brew 安装最新版本的 Node

macos - 运行需要从根终端访问钥匙串(keychain)的 cocoa 应用程序

iphone - 实现对 iphone/ipad 的传真支持

iphone - 列出 Cocoa 中所有已连接的 iDevices

usb-drive - 将 USB 磁盘 BSD 名称映射到 OSX 中实际安装的驱动器

macos - 从 View 、字符串等创建图像

macos - osx - 使用 mpv 或 mplayer 与 libcaca 或 aalib 在终端中以文本形式播放 youtube 视频?

objective-c - 类别中的私有(private)方法,使用匿名类别

macos - 带 socket 的自定义 NSView