2012-04-24 81 views
1

我正在使用FSCopyObjectAsync跨卷复制文件。我已经使用cimgf的代码让我走了,它工作得很好。在后台线程上不会调用FSCopyObjectAsync回调方法

我最近遇到的问题之一是复制状态回调不会发生在后台线程上。当我没有通过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); 
    } 
} 

任何帮助或洞察力的赞赏!

+0

请显示代码的其余部分,包括您在哪里进行dispatch_async调用以及运行后台线程运行循环的代码。 – 2012-04-24 22:04:44

+0

@PeterHosey好主意。刚添加完整的代码。谢谢 – Westley 2012-04-24 22:43:34

回答

2

问题是,您正在使用dispatch_async,但FSCopyObjectAsync将复制操作回调绑定到特定的runloop,从而特定的线程。

你需要做的是使用dispatch_async,但无论哪种:

  1. 执行主线程复制操作(这大概应该是OK,以同样的方式,在执行上的NSURLConnection主线程正常)
  2. 分拆第二个NSThread,在该线程上安排操作,然后通过调用[[NSRunLoop currentRunLoop] run](或相应的变体)启动runloop运行。
+0

谢谢戴夫,你是男人! – Westley 2012-04-25 21:22:27

相关问题