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);
}
}
どんな助けや洞察も大歓迎です!