Используя дисковые арбитражные обратные вызовы уведомления и утверждения
Когда те уведомления происходят, наиболее распространенный способ использовать Дисковый Арбитраж состоит в том, чтобы зарегистрироваться для уведомлений и затем принять некоторые меры. Например, когда новый диск появляется, Вы могли бы спросить, хочет ли пользователь использовать его в качестве резервного места назначения. Можно также зарегистрировать обратные вызовы утверждения, если приложение должно участвовать в арбитражном процессе — например, помощь решают, должен ли диск быть смонтирован или извлечен.
Эта глава говорит, как использовать уведомление и механизмы утверждения, предоставленные Дисковой Арбитражной платформой, вместе со связанными понятиями в порядке, в котором необходимо понять их при записи дисковому арбитражному клиенту с нуля. Если Вы не хотите использовать уведомление или аспекты утверждения дискового арбитража, пропустите к следующей главе, Управляя Дисками и Объемами.
Если Ваше приложение должно зарегистрироваться для уведомления или участвовать в арбитражном процессе, это должно сделать следующее:
Создайте объект сеанса путем вызова
DASessionCreate
.Обратные вызовы уведомления регистра, если Вы хотите знать, когда связанный с диском случай происходит, или обратные вызовы утверждения регистра, если Вы хотите активно участвовать в арбитражном процессе.
Запланируйте объект сеанса на цикл выполнения или диспетчеризируйте очередь (и запустите цикл выполнения или диспетчеризируйте очередь, если необходимый).
Обработайте любые обратные вызовы, которые получает Ваше приложение.
Когда приложение больше не должно будет получать обратные вызовы, не запланируйте объект сеанса и выпустите его.
Создание сеанса
Первая вещь, которую необходимо сделать при записи дисковому арбитражному клиенту уведомления, создают сеанс (DASessionRef
). Для создания дискового арбитражного сеанса вызвать DASessionCreate
, как показано ниже:
DASessionRef session; |
session = DASessionCreate(kCFAllocatorDefault); |
Регистрация для уведомлений и утверждений
Существует два типа обратных вызовов, поддерживаемых дисковым арбитражем. Обратные вызовы уведомления говорят Вам, что что-то произошло. Обратные вызовы утверждения позволяют, Вы для предотвращения монтируете, размонтировали или извлекаете действия от случая.
Обратные вызовы уведомления
Существует четыре типа обратных вызовов уведомления:
DADiskAppearedCallback
— вызванный, когда диск появляется или раздел появляетсяDADiskDescriptionChangedCallback
— вызванный, когда описание диска изменилось (и, в OS X v10.7 и позже, когда объем сначала смонтирован),DADiskDisappearedCallback
— вызванный, когда извлекается съемный дискDADiskPeekCallback
— вызванный, когда диск сначала зондируется, прежде чем автоматическое монтирование начинается, и прежде чем любые другие уведомления будут отосланы),
У каждого есть его собственная регистрационная функция (DARegisterDiskAppearedCallback
, DARegisterDiskDescriptionChangedCallback
, DARegisterDiskDisappearedCallback
, и DARegisterDiskPeekCallback
).
Большинство этих регистрационных функций берет соответствующий словарь. Необходимо обычно передавать NULL
(чтобы соответствовать все диски) или передать стандартный словарь соответствия такой как kDADiskDescriptionMatchMediaUnformatted
. Подробное поведение при сравнении этих словарей соответствия показано в Таблице 1-1.
Стандартный словарь | Содержание | Описание |
---|---|---|
| Соответствия восстановили после форматирования носители (такие как пустой DVD). | |
| Соответствия только целый дисковый носитель ( | |
| Соответствует монтируемые объемы. | |
| Соответствует немонтируемые диски. |
Например, для ограничения соответствия присоединенными к USB носителями Вы могли бы создать соответствующий словарь как это:
CFMutableDictionaryRef matchingDict = |
CFDictionaryCreateMutable( |
kCFAllocatorDefault, |
0, |
&kCFTypeDictionaryKeyCallBacks, |
&kCFTypeDictionaryValueCallBacks); |
CFDictionaryAddValue(matchingDict, |
kDADiskDescriptionDeviceProtocolKey, |
CFSTR(kIOPropertyPhysicalInterconnectTypeUSB)); |
Дополнительные взаимосвязанные типы и другие связанные константы описаны в Ссылке Пространства пользователя IOStorageProtocolCharacteristics.h.
Наконец, можно передать произвольные данные обратному вызову каждый раз, когда дисковое событие соответствует указанный словарь соответствия (или словари) и тип события с помощью указателя контекста. Путем передачи различных указателей контекста можно зарегистрировать тот же обратный вызов многократно в различном словаре соответствия и предоставить информацию обратному вызову, указывающему, какая регистрация соответствовала. Если Вы не должны предоставлять такую контекстную информацию, просто передайте NULL
для этого параметра.
Подробные данные каждого обратного вызова описаны более подробно в следующих разделах.
Наблюдение за новыми дисками или разделами
Для наблюдения за новыми дисками или разделами вызвать DARegisterDiskAppearedCallback
. Например:
void got_disk(DADiskRef disk, void *context); |
... |
void *context = NULL; |
DARegisterDiskAppearedCallback(session, |
kDADiskDescriptionMatchVolumeMountable, |
got_disk, context); |
void got_disk(DADiskRef disk, void *context) |
{ |
printf("Got new disk\n"); |
} |
Этот пример использует kDADiskDescriptionMatchVolumeMountable
соответствие словаря для ограничения обратных вызовов монтируемыми дисками. Можно также ограничить обратные вызовы немонтируемыми дисками или целыми разделами носителей (/dev/disk1
, например). Для списка предопределенных словарей см. документацию для DiskArbitration.h
.
Наблюдение за дисковым исчезновением
Чтобы быть уведомленным, когда диск будет извлечен (ли пользователем, извлекающим его или отключающим устройство), вызвать DARegisterDiskDisappearedCallback
. Например:
void got_disk_removal(DADiskRef disk, void *context); |
... |
/* Match all volumes */ |
CFDictionaryRef matchingdictionary = NULL; |
/* No context needed here. */ |
void *context = NULL; |
DARegisterDiskDisappearedCallback(session, |
matchingdictionary, |
got_disk_removal, |
context); |
... |
void got_disk_removal(DADiskRef disk, void *context) |
{ |
printf("Disk removed: %s\n", DADiskGetBSDName(disk)); |
} |
Наблюдение за дисковыми изменениями описания и получение информации о точке монтирования
Дисковое описание предоставляет информацию о диске, включая то, отформатировано ли это, точка монтирования, имя тома, и т.д. Можно наблюдать за изменениями в этой информации путем вызова DARegisterDiskDescriptionChangedCallback
.
Когда Ваш обратный вызов вызывают, это добирается, три значения передали в: ссылка на диск (или раздел), a CFArrayRef
объект, содержащий список ключей, изменившихся, и указатель контекста, который Вы передали в том, когда Вы зарегистрировали обратный вызов.
Например, если Вы хотите узнать новую точку монтирования (/Volumes/My Disk/
, например) после того, как объем переименован, Вы могли бы смотреть для разнообразия по пути объема при помощи kDADiskDescriptionWatchVolumePath
соответствие словаря.
void got_rename(DADiskRef disk, CFArrayRef keys, void *context); |
... |
CFMutableArrayRef keys = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); |
CFArrayAppendValue(keys, kDADiskDescriptionVolumeNameKey); |
DARegisterDiskDescriptionChangedCallback(session, |
NULL, /* match all disks */ |
keys, /* match the keys specified above */ |
got_rename, |
NULL); |
... |
void got_rename(DADiskRef disk, CFArrayRef keys, void *context) |
{ |
CFDictionaryRef dict = DADiskCopyDescription(disk); |
CFURLRef fspath = CFDictionaryGetValue(dict, kDADiskDescriptionVolumePathKey); |
char buf[MAXPATHLEN]; |
if (CFURLGetFileSystemRepresentation(fspath, false, (UInt8 *)buf, sizeof(buf))) { |
printf("Disk %s is now at %s\nChanged keys:\n", DADiskGetBSDName(disk), buf); |
CFShow(keys); |
} else { |
/* Something is *really* wrong. */ |
} |
} |
Наблюдение за новыми физическими средами
Чтобы быть уведомленным, когда новый диск появляется, перед, автоматическое монтирование происходит, использовать DARegisterDiskPeekCallback
.
В отличие от предыдущих уведомлений, когда Вы регистрируетесь для дискового обратного вызова быстрого взгляда, Вы передаете дополнительный параметр, order
, который позволяет Вам устанавливать порядок, в котором Ваши обратные вызовы вызывают относительно других обратных вызовов быстрого взгляда. Если у Вас нет причины сделать иначе, передайте нуль (0
).
Следующий отрывок показывает, как использовать дисковый обратный вызов быстрого взгляда для требования объема. Этот метод обычно используется программным обеспечением, таким как iTunes для требования пустых носителей его собственное использование так, чтобы OS X не спрашивал пользователя, что сделать.
void got_disk(DADiskRef disk, void *context); |
void myreleasecallback(DADiskRef disk, void *context); |
void myclaimcallback(DADiskRef disk, DADissenterRef dissenter, void *context); |
DARegisterDiskPeekCallback(session, |
kDADiskDescriptionMatchVolumeMountable, |
0, |
got_disk, |
NULL); |
void got_disk(DADiskRef disk, void *context) |
{ |
printf("Got new disk\n"); |
/* Claim the disk exclusively. */ |
DADiskClaim(disk, |
kDADiskClaimOptionDefault, |
myreleasecallback, |
NULL, |
myclaimcallback, |
NULL /* Or optional context */ |
); |
/* Do other stuff here... */ |
} |
Нерегистрация обратного вызова
Когда Вы больше не нуждаетесь в обратном вызове уведомления, не регистрируете его путем вызова DAUnregisterCallback
. Например:
DAUnregisterCallback(session, mycallbackfuntion, NULL); |
Обязательно передайте в исходном значении указателя контекста, которое Вы использовали при регистрации функции.
Обратные вызовы утверждения
Можно зарегистрировать обратные вызовы утверждения в дисковом арбитраже тремя способами, в зависимости от того, когда Вы хотите быть уведомленными.
Если Вы хотите попроситься разрешения, прежде чем диск будет извлечен, вызвать
DARegisterDiskEjectApprovalCallback
.Если Вы хотите попроситься разрешения, прежде чем объем будет смонтирован, вызвать
DARegisterDiskMountApprovalCallback
.Если Вы хотите попроситься разрешения, прежде чем объем будет размонтирован, вызвать
DARegisterDiskUnmountApprovalCallback
.
Как обратные вызовы уведомления, эти регистрационные функции берут четыре параметра: сеанс, соответствующий словарь, подпрограмма обратного вызова и указатель контекста.
Для соответствующего словаря Вы обычно передаете NULL
(чтобы соответствовать все диски) или передать стандартный словарь соответствия такой как kDADiskDescriptionMatchMediaUnformatted
. Эти стандартные словари документируются в раздел Globals документации для DiskArbitration.h
.
Наконец, можно передать произвольные данные обратному вызову каждый раз, когда дисковое событие соответствует указанный словарь соответствия (или словари) и тип события с помощью указателя контекста. Путем передачи различных указателей контекста можно зарегистрировать тот же обратный вызов многократно в различном словаре соответствия и предоставить информацию обратному вызову, указывающему, какая регистрация соответствовала. Если Вы не должны предоставлять такую контекстную информацию, просто передайте NULL
для этого параметра.
Утверждение или отказ от запроса
После регистрации подпрограммы обратного вызова для типа определенного события каждый раз, когда событие того типа имеет место, Дисковый Арбитраж вызывает функцию обратного вызова, передавая его указатель контекста, который Вы указали ранее, вместе с дисковым объектом (DADiskRef
).
В Вашей функции обратного вызова необходимо проверить дисковый объект по мере необходимости, чтобы определить, позволить ли событие (см. Диски Управления и Объемы). Тогда:
Возвратиться
NULL
если Вы хотите позволить работе завершаться.Возвратите a
DADissenterRef
возразите для отмены работы.
Когда Вы создаете DADissenterRef
объект, набор состояние к одному из кодов состояния в DAReturn
, и набор строка состояния к a CFStringRef
объект, содержащий надлежащее объяснение.
Например:
DADissenterRef allow_mount(DADiskRef disk, void *context); |
... |
session = DASessionCreate(kCFAllocatorDefault); |
DARegisterDiskMountApprovalCallback(session, |
NULL, /* Match all disks */ |
allow_mount, |
NULL); /* No context */ |
... |
DADissenterRef allow_mount( |
DADiskRef disk, |
void *context) |
{ |
int allow = 0; |
if (allow) { |
/* Return NULL to allow */ |
fprintf(stderr, "allow_mount: allowing mount.\n"); |
return NULL; |
} else { |
/* Return a dissenter to deny */ |
fprintf(stderr, "allow_mount: refusing mount.\n"); |
return DADissenterCreate( |
kCFAllocatorDefault, kDAReturnExclusiveAccess, |
CFSTR("It's mine!")); |
} |
} |
Нерегистрация обратного вызова
Когда Вам больше не нужен обратный вызов утверждения, необходимо не зарегистрировать его путем вызова DAUnregisterApprovalCallback
. Например:
DAUnregisterApprovalCallback(session, mycallbackfuntion, NULL); |
Обязательно передайте в исходном значении указателя контекста, которое Вы использовали при регистрации функции.
Планирование сеанса с очередью цикла или отгрузки выполнения
Последняя вещь, которую необходимо сделать, чтобы заставить обратные вызовы фактически вызываться, состоит в том, чтобы запланировать дисковый арбитражный сеанс с циклом выполнения или очередью отгрузки (и, при необходимости, запустите цикл выполнения). Путем Вы планируете сеанс, зависит от того, используете ли Вы Центральные очереди Отгрузки или цикл выполнения (в Базовой Основе или Основе).
Используя очереди отгрузки
При использовании Центральной Отгрузки можно запланировать и не запланировать дисковый арбитражный сеанс путем вызова DASessionSetDispatchQueue
, определенный в DASession.h
.
Следующий фрагмент кода показывает, как запланировать сеансы, сеансы нерасписания, и высвободить средства, связанные с сеансами:
/* Schedule the session on a dispatch queue. */ |
DASessionSetDispatchQueue(session, queue); |
/* Unschedule the session on a dispatch queue. */ |
DASessionSetDispatchQueue(session, NULL); |
/* Clean up the session resources. */ |
CFRelease(session); |
Используя цикл выполнения
При использовании Базовой Основы или Основы выполненный цикл можно запланировать дисковый арбитражный сеанс путем вызова DASessionScheduleWithRunLoop
, определенный в DASession.h
.
Следующий фрагмент кода показывает, как запланировать сеансы с циклом выполнения, запустите цикл выполнения, не запланируйте сеансы и высвободите средства, связанные с ними:
/* Schedule a disk arbitration session. */ |
DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); |
/* Start the run loop. (Don't do this if you already have |
a running Core Foundation or Cocoa run loop.) */ |
CFRunLoopRun(); |
/* Clean up a session. */ |
DASessionUnscheduleFromRunLoop(session, |
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); |
CFRelease(session); |