Отображение прогресса копирования файлов с использованием FscopyObjectAsync
-
05-10-2019 - |
Вопрос
Он появляется после многих поисков, что, кажется, распространена проблема при попытке выполнить копию файла и показать индикатор прогресса относительно количества копированного файла. Потратив значительное время, пытаясь решить эту проблему, я нахожусь во власти богов Stackoverflow еще раз :-) - надеюсь, однажды я тоже буду среди тем, кто может помочь новичкам!
Я пытаюсь получить панель прогресса, чтобы показать состояние процесса копирования, и после завершения процесса копирования вызовите метод какао. Задача - мне нужно использовать Carbon Carbon Carbon, потому что nsfilemanager не дает мне полную способность, которые мне нужно.
Я начал, пытаясь использовать код на Matt Long's Site Какао - моя подруга. Отказ Код получил мне хорошее расстояние. Мне удалось запустить прогресс копии файлов. Обновления бара и (с некоторыми дополнительными поисками в Apple Docs) Я узнал, как сказать, если процесс копирования файлов завершится ...
if (stage == kFSOperationStageComplete)
Тем не менее, у меня есть последний препятствие, который сейчас немного больше, чем мой прыжок. Я не знаю, как пройти ссылку на ссылку на обратную связь, и я не знаю, как позвонить в метод какао из обратного вызова после завершения. Это предел моего углерода -> какао -> понимание углерода. Один из комментариев в блоге сказал
«Вместо того, чтобы получить доступ к индикатору прогресса через статический указатель, вы можете просто использовать Void * Info поле FSFileoPerationClientContext Struction и прохождение 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...
}
}
Так что нижняя строка - как я могу:
- Пройдите указатель на экземпляр панели выполнения из метода вызывающего обратного вызова
- После завершения обратно обратно в нормальный метод какао
И как всегда, помощь очень ценится (и, надеюсь, ответ решит многие проблемы и жалобы, которые я видел во многих потоках !!)
Решение
Вы можете сделать это, используя последний параметр для FSCopyObjectAsync()
, что является структурой типа FSFileOperationClientContext
. Отказ Один из областей этой структуры info
, который является параметром void *, который вы можете в основном использовать, как вы видите. Что бы вы ни присваиваете этому сферу структуры, в которое вы переходите FSCopyObjectAsync()
будет передан в свою очередь к функции обратного вызова в качестве последней info
Функциональный параметр там. Пустота * может быть что-нибудь, включая указатель на объект, поэтому вы можете использовать это, чтобы пройти экземпляр вашего объекта, который вы хотите обрабатывать обратный вызов.
Код установки будет выглядеть так:
FSFileOperationClientContext clientContext = {0}; //zero out the struct to begin with
clientContext.info = myProgressIndicator;
//All the other setup code
status = FSCopyObjectAsync (fileOp,
&source,
&destination, // Full path to destination dir
targetFilename,
kFSFileOperationDefaultOptions,
statusCallback,
1.0,
&clientContext);
Затем в вашей функции обратного вызова:
static void statusCallback (FSFileOperationRef fileOp,
const FSRef *currentItem,
FSFileOperationStage stage,
OSStatus error,
CFDictionaryRef statusDictionary,
void *info )
{
NSProgressIndicator* fileProgressIndicator = (NSProgressIndicator*)info;
[fileProgressIndicator setDoubleValue:(double)floatBytesCompleted];
[fileProgressIndicator displayIfNeeded];
}