Отображение прогресса копирования файлов с использованием FscopyObjectAsync

StackOverflow https://stackoverflow.com/questions/3784230

Вопрос

Он появляется после многих поисков, что, кажется, распространена проблема при попытке выполнить копию файла и показать индикатор прогресса относительно количества копированного файла. Потратив значительное время, пытаясь решить эту проблему, я нахожусь во власти богов 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...
}

} 

Так что нижняя строка - как я могу:

  1. Пройдите указатель на экземпляр панели выполнения из метода вызывающего обратного вызова
  2. После завершения обратно обратно в нормальный метод какао

И как всегда, помощь очень ценится (и, надеюсь, ответ решит многие проблемы и жалобы, которые я видел во многих потоках !!)

Это было полезно?

Решение

Вы можете сделать это, используя последний параметр для 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];
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top