1

FSCopyObjectAsyncボリューム間でファイルをコピーするために使用しています。cimgfのコードを使用して作業を進めましたが、かなりうまく機能しています。

私が最後に直面した問題の 1 つは、バックグラウンド スレッドでコピー ステータス コールバックが発生していないことです。でコピー操作を開始しないdispatch_async(copyQueue, ^{と、コールバックが完全に呼び出されます。バックグラウンドに移動すると、発火しません。コードは次のとおりです。

//Excerpt from existing method
// Create the semaphore, specifying the initial pool size
fd_sema = dispatch_semaphore_create(1);

dispatch_queue_t copyQueue = dispatch_queue_create("copy.theQueue", 0);
dispatch_group_t group = dispatch_group_create();

for(SearchPath * p in searchPaths) {
    dispatch_async(copyQueue, ^{
        
        NSString * newDestination = [NSString stringWithFormat:@"%@%@",destination,p.relativePath];
        NSString * source = [NSString stringWithFormat:@"%@%@",p.basePath,p.relativePath];
        NSError * error = nil;
        
        //Wait until semaphore is available  
        dispatch_semaphore_wait(fd_sema, DISPATCH_TIME_FOREVER);
        
        //Update progress window text
        [progressview.label setStringValue:[NSString stringWithFormat:@"Copying \"%@\" to \"%@\"",[source lastPathComponent],[destination lastPathComponent]]];
        
        if(p.isDirectory) {
            
            BOOL result = [[NSFileManager defaultManager] createDirectoryAtPath:newDestination withIntermediateDirectories:NO attributes:nil error:nil];
            
            if(result) {
                //Item was a directory
                dispatch_semaphore_signal(fd_sema);
            }
            
        }else{
            
            [self startCopy:source dest:[newDestination stringByDeletingLastPathComponent]];
            
        }
        
        if(error) {
            MTLogDebug(@"Error! : %ld", error.code);
        }
    }); //End async
} //End for loop

//End excerpt  

- (void)startCopy:(NSString *)source dest:(NSString *) destination
{
    // Get the current run loop and schedule our callback
    //TODO:Make this work while on a background thread
    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;
    }

    // Create a filesystem ref structure for the source and destination and
    // populate them with their respective paths from our NSTextFields.
    FSRef sourceRef;
    FSRef destinationRef;

    //FSPathMakeRef( (const UInt8 *)[source fileSystemRepresentation], &sourceRef, NULL );
    FSPathMakeRefWithOptions((const UInt8 *)[source fileSystemRepresentation],
                             kFSPathMakeRefDefaultOptions, 
                             &sourceRef, 
                             NULL);

    Boolean isDir = true;
    //FSPathMakeRef( (const UInt8 *)[destination fileSystemRepresentation], &destinationRef, &isDir );    
    FSPathMakeRefWithOptions((const UInt8 *)[destination fileSystemRepresentation],
                             kFSPathMakeRefDefaultOptions, 
                             &destinationRef, 
                             &isDir);

    // Start the async copy.
    status = FSCopyObjectAsync (fileOp,
                                &sourceRef,
                                &destinationRef, // Full path to destination dir
                                NULL, // Use the same filename as source
                                kFSFileOperationDefaultOptions,
                                statusCallback,
                                0.1,
                                NULL);
    NSLog(@"Stat: %d",status);
    CFRelease(fileOp);

    if(status) {
        NSLog(@"Failed to begin asynchronous object copy: %d", status);
    }
}

static void statusCallback (FSFileOperationRef fileOp,
                            const FSRef *currentItem,
                            FSFileOperationStage stage,
                            OSStatus error,
                            CFDictionaryRef statusDictionary,
                            void *info)
{
    if (statusDictionary) {
        
        NSNumber *bytesCompleted = (__bridge NSNumber *) CFDictionaryGetValue(statusDictionary, kFSOperationBytesCompleteKey);
        
        NSURL *url = (__bridge NSURL *)convertedURLRef;
        
        if([bytesCompleted intValue] > 0) {
            
            if(stage == kFSOperationStageRunning) {
                
                //Update progress indicator
                [progressview.indicator setDoubleValue:progressview.indicator.doubleValue + [newNumberValue floatValue]];           
            }
        }
    }
    
    if (stage == kFSOperationStageComplete) {
        dispatch_semaphore_signal(fd_sema);
    }
}

どんな助けや洞察も大歓迎です!

4

1 に答える 1

2

問題は、これをdispatch_asyncで使用しているがFSCopyObjectAsync、コピー操作のコールバックを特定の実行ループ、つまり特定のスレッドに結び付けていることです。

あなたがする必要があるのは、を使用することではなくdispatch_async、次のいずれかです。

  1. メインスレッドでコピー操作を実行します(メインスレッドで実行するのと同じように、おそらく問題ないはずNSURLConnectionです)
  2. セカンダリをスピンオフし、そのスレッドで操作をスケジュールしてから、 (または適切なバリアント)NSThreadを呼び出して runloop の実行を開始します。[[NSRunLoop currentRunLoop] run]
于 2012-04-25T21:15:20.500 に答える