#objective-c #cocoa #nstask
#objective-c #cocoa #nstask
Вопрос:
Я пытаюсь заархивировать файлы с помощью утилиты командной строки через NSTask.
псевдокод:
controller:
init:
register_self_as_observer_of_nstask_notifications
startZip(file):
file = somefileobject
task = "zip" with file path as argument
task.launch
notification_listener(notification):
task = notification.get_object
file = task.???
Итак, как я могу узнать, к какому файловому объекту относится уведомление? Обычно я использую словарь userInfo для таких вещей, но у NSTask нет такой опции. От Apple Dev: Это уведомление не содержит словарь userInfo.
Спасибо!
Комментарии:
1. Один экземпляр контроллера порождает более одной задачи одновременно?
2. Да, это так. Вот почему мне нужен способ связать задачи с файлами.
3. Это одна из первых вещей, которые я попробовал, но NSDictionary пытается скопировать задачу, когда она используется в качестве ключа, а NSTask не реализует NSCopying.
Ответ №1:
Используйте связанный объектный API, чтобы прикрепить словарь user info к экземпляру задачи. Это был бы самый чистый подход, но его нельзя использовать до внедрения связанного объектного API в Mac OS X 10.6.
В качестве альтернативы вы можете использовать словарь, который сопоставляет информацию о задаче с информацией о пользователе. Создание сопоставления словаря из задачи с информацией пользователя не так просто, как кажется:
- Вы не можете просто
[taskInfoDict setObject:userInfo forKey:task]
потомуNSTask
, что он не соответствуетNSCopying
, ноNSDictionary
полагается на копирование его ключей. - Использование идентификатора процесса, завернутого в
NSNumber
, в качестве прокси для объекта task в основном работает. Но идентификаторы процессов можно использовать повторно, и задача не получает PID до тех пор, пока она не будет запущена. Корень проблемы в том, что вы не управляете идентификатором процесса; это делает базовая ОС.
Использование адреса объекта task кажется лучшим решением:
[taskInfoDict setObject:userInfo forKey:[NSValue valueWithPointer:task]]
Предполагая среду с подсчетом ссылок, адрес объекта задачи будет стабильным в течение всего срока службы, а его срок службы полностью контролируется вашим приложением. Копирующий сборщик мусора внес бы коррективы в это решение, но в этом случае вы могли бы использовать класс collection, который может обрабатывать указатель напрямую ( NSMapTable
).
Комментарии:
1. Это одна из первых вещей, которые я попробовал, но NSDictionary пытается скопировать задачу, когда она используется в качестве ключа, а NSTask не реализует NSCopying.
2. Не могли бы вы использовать идентификатор процесса задачи (завернутый в
NSNumber
) в качестве ключа?3. @Alexandre: Используйте
NSValue
перенос адреса задачи в качестве ключа вместо самогоNSTask
объекта. И связанный объектный подход не зависит от того,NSTask
соответствуетNSCopying
или нет.4. В итоге я согласился с предложением Wevah (см. Выше) использовать pid NSTask в качестве ключа словаря, и это прекрасно сработало. Вы видите какую-либо причину не делать этого?
5. Идентификаторы процессов можно использовать повторно, и задача не получает идентификатор процесса до его запуска. Адрес задачи полностью находится под контролем вашего приложения. (Хотя связанный объектный подход является самым чистым из всех.)
Ответ №2:
Рассмотрите возможность использования ассоциативных ссылок для привязки URL-адреса файла / пути к каждому экземпляру задачи. У каждого объекта может быть несколько связанных объектов, и у каждого связанного объекта есть соответствующий ключ, который используется для ссылки на связанный объект, когда это необходимо.
В вашем контроллере создайте static
переменную, которая представляет URL-адрес файла / ключ пути:
static char fileURLKey;
При создании NSTask
экземпляра свяжите соответствующий URL-адрес файла с этим экземпляром:
NSURL *fileURL = …;
NSTask *task = …;
objc_setAssociatedObject(task, amp;fileURLKey, fileURL, OBJC_ASSOCIATION_RETAIN);
Когда задача завершит выполнение, получите задачу из объекта notification, а затем получите URL-адрес файла из задачи:
NSTask *task = [notification object];
NSURL *fileURL = (NSURL *)objc_getAssociatedObject(task, amp;fileURLKey);
Комментарии:
1. В итоге я согласился с предложением Wevah (см. Выше) использовать pid NSTask в качестве ключа словаря, и это прекрасно сработало. Вы видите какую-либо причину не делать этого?
2. @Alex Ну, я нахожу ассоциативные ссылки более простыми и общими. В итоге вы использовали словарь и управляли им вручную, тогда как ассоциативные ссылки выполняют эту работу за вас автоматически.
3. Хорошо, я попытаюсь заменить подход Dict вашим подходом. Спасибо!
4. О-о, только что заметил, что этот метод доступен только для версии 10.6. Все еще много пользователей Leopard. Метод Wevah кажется более совместимым.
5. Ответ Алекса Джереми — самый подходящий ответ, если вы ориентируетесь на Leopard.