1

FSCopyObjectAsync用来跨卷复制文件。我已经使用cimgf中的代码让我继续前进,并且运行良好。

我挂断的最后一个问题是复制状态回调没有发生在后台线程上。当我不通过 开始复制操作时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线程,在该线程上安排操作,然后通过调用[[NSRunLoop currentRunLoop] run](或适当的变体)启动运行循环。
于 2012-04-25T21:15:20.500 回答