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

После долгих поисков выяснилось, что существует общая проблема при попытке скопировать файл и отображается индикатор выполнения относительно объема скопированного файла. Потратив немало времени на решение этой проблемы, я снова оказался во власти богов StackOverflow :-) - Надеюсь, однажды я буду среди тех, кто тоже сможет помочь новичкам!

Я пытаюсь получить индикатор выполнения, чтобы показать состояние процесса копирования, и после завершения процесса копирования вызвать метод Какао. Проблема - мне нужно использовать вызовы File Manager Carbon, потому что NSFileManager не дает мне всех необходимых мне возможностей.

Я начал с попытки использовать код на сайте Мэтта Лонга Cocoa Is My Girlfriend . Код дал мне хорошее расстояние. Мне удалось заставить работать процесс копирования файла. Панель обновляется, и (с дополнительным поиском в документации Apple) я узнал, как узнать, завершился ли процесс копирования файла ...

if (stage == kFSOperationStageComplete)

Однако у меня есть последнее препятствие, которое немного больше, чем мой прыжок прямо сейчас. Я не знаю, как передать ссылку на объект в обратный вызов, и я не Я не знаю, как вызвать метод Какао из обратного вызова после завершения. Это предел моего понимания Углерода -> Какао -> Углерод. В одном из комментариев к блогу

сказано: «Вместо доступа к индикатору прогресса через статический указатель, вы можете просто использовать поле void * info структуры 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...
}

} 

Итак, суть в том, как я могу:

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

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

7
задан Hooligancat 24 September 2010 в 04:39
поделиться