После многократного поиска появляется много проблем при попытке сделать копию файла и отобразить индикатор прогресса относительно объема файла, который был скопирован. Проведя некоторое время, пытаясь решить эту проблему, я снова нахожусь во власти богов StackOverflow :-) - Надеюсь, однажды я буду среди тех, кто может помочь новичкам!Отображение прогресса копирования файла с использованием FSCopyObjectAsync
Я пытаюсь получить индикатор выполнения, чтобы показать статус процесса копирования, и как только процесс копирования завершится, вызовите метод Cocoa. Задача - мне нужно использовать вызовы File Manager Carbon, потому что NSFileManager не дает мне полной возможности, в которой я нуждаюсь.
Я начал с попытки использовать код на сайте Мэтта Лонга Cocoa Is My Girlfriend. Код дал мне хорошее расстояние. Мне удалось добиться успеха в копировании файлов. Обновления бара и (с некоторым дополнительным поиском в Apple, документы), которые я нашел, как сказать, если процесс копирования файлов закончило ...
if (stage == kFSOperationStageComplete)
Однако, у меня есть один последний барьер, который немного больше, чем мой прыжок прямо сейчас. Я не знаю, как передать ссылку на объект в обратный вызов, и я не знаю, как вызвать метод Какао из обратного вызова после его завершения. Это предел моего понимания Carbon -> Cocoa -> Carbon. Один из комментариев на блоге сказал
«Вместо того, чтобы получить доступ к индикатору прогресса через статический указатель, вы можете просто использовать пустое * информационное поле от структуры FSFileOperationClientContext и переходя либо в AppDelegate или сам индикатор прогресса «.
Звучит отличная идея. Не знаете, как это сделать. Ради всех остальных, которые, похоже, сталкиваются с этой проблемой и исходят из некарбонового фона, основанного главным образом на коде из примера Мэтта, вот пример упрощенного кода в качестве примера проблемы ...
в обычном способе какао:
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
FSFileOperationRef fileOp = FSFileOperationCreate(kCFAllocatorDefault);
OSStatus status = FSFileOperationScheduleWithRunLoop(fileOp,
runLoop, kCFRunLoopDefaultMode);
if (status) {
NSLog(@"Failed to schedule operation with run loop: %@", status);
return NO;
}
// Create a filesystem ref structure for the source and destination and
// populate them with their respective paths from our NSTextFields.
FSRef source;
FSRef destination;
// Used FSPathMakeRefWithOptions instead of FSPathMakeRef which is in the
// original example because I needed to use the kFSPathMakeRefDefaultOptions
// to deal with file paths to remote folders via a /Volume reference
FSPathMakeRefWithOptions((const UInt8 *)[aSource fileSystemRepresentation],
kFSPathMakeRefDefaultOptions,
&source,
NULL);
Boolean isDir = true;
FSPathMakeRefWithOptions((const UInt8 *)[aDestDir fileSystemRepresentation],
kFSPathMakeRefDefaultOptions,
&destination,
&isDir);
// Needed to change from the original to use CFStringRef so I could convert
// from an NSString (aDestFile) to a CFStringRef (targetFilename)
CFStringRef targetFilename = (CFStringRef)aDestFile;
// Start the async copy.
status = FSCopyObjectAsync (fileOp,
&source,
&destination, // Full path to destination dir
targetFilename,
kFSFileOperationDefaultOptions,
statusCallback,
1.0,
NULL);
CFRelease(fileOp);
if (status) {
NSString * errMsg = [NSString stringWithFormat:@"%@ - %@",
[self class], status];
NSLog(@"Failed to begin asynchronous object copy: %@", status);
}
Тогда обратного вызова (в том же файле)
static void statusCallback (FSFileOperationRef fileOp,
const FSRef *currentItem,
FSFileOperationStage stage,
OSStatus error,
CFDictionaryRef statusDictionary,
void *info)
{
NSLog(@"Callback got called.");
// If the status dictionary is valid, we can grab the current values to
// display status changes, or in our case to update the progress indicator.
if (statusDictionary)
{
CFNumberRef bytesCompleted;
bytesCompleted = (CFNumberRef) CFDictionaryGetValue(statusDictionary,
kFSOperationBytesCompleteKey);
CGFloat floatBytesCompleted;
CFNumberGetValue (bytesCompleted, kCFNumberMaxType,
&floatBytesCompleted);
NSLog(@"Copied %d bytes so far.",
(unsigned long long)floatBytesCompleted);
// fileProgressIndicator is currently declared as a pointer to a
// static progress bar - but this needs to change so that it is a
// pointer passed in via the controller. Would like to have a
// pointer to an instance of a progress bar
[fileProgressIndicator setDoubleValue:(double)floatBytesCompleted];
[fileProgressIndicator displayIfNeeded];
}
if (stage == kFSOperationStageComplete) {
NSLog(@"Finished copying the file");
// Would like to call a Cocoa Method here...
}
}
Таким образом, нижняя линия как я могу:
- передать указатель на экземпляр индикатора выполнения от способа вызова функции обратного вызова
- После завершения обратного вызова к нормальному способу какао
И как всегда, помощь очень ценится (и, надеюсь, ответ решает многие проблемы и жалобы, которые я видел во многих потоках !!)
Брайан спасибо !!! Теперь я вижу это, решение кажется таким простым! Я закончил инициализацию экземпляра класса, чтобы полностью обработать панель прогресса и передал этот экземпляр класса в clientContext. Мне удалось обновить индикатор выполнения и вызвать вызовы методов для класса. Я отправлю полное решение для тех, кто не совсем следил за моими последними комментариями, когда я получаю мгновение. Еще раз спасибо Брайан! – Hooligancat
@Hooligancat Можете ли вы разместить свое полное решение? У меня та же проблема: я хотел бы передать экземпляр класса в clientContext, но я не знаю, как это сделать. – FR6
@ FR6 - Я не коснулся этого кода через некоторое время, но я возьму копание и посмотрю, смогу ли я найти его для вас и разместить весь код. Оставайтесь с нами ... – Hooligancat