2012-04-24 66 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

相關問題