0

我正在尝试使用 Objective-C/XCode 编写一个程序,将一个目录(源目录)备份到另一个目录(目标目录)。

当我在本地机器上的一个小目录上测试程序时,它按预期工作。但是,当我尝试使用大型目录或网络上的任何内容时,该程序就会出现问题。我知道线程是答案。鉴于以下代码,我可以看出我一直在摆弄各种方法来做到这一点。任何人都可以帮忙吗?我似乎无法正常工作。这是有问题的代码/方法:

- (void)doSync:(NSString *)sURL {
bStopCopy = NO;
NSString *sSource = [[pcSource URL] path];
NSString *sDestination = [[pcDestination URL] path];
NSString *sSourcePath = [sSource stringByAppendingString:@"/"];
NSString *sDestinationPath = [sDestination stringByAppendingString:@"/"];
NSString *sSourceFile;
NSString *sDestinationFile;
NSString* file;
NSDirectoryEnumerator* enumerator = [[NSFileManager defaultManager] enumeratorAtPath:sURL];

while ((file = [enumerator nextObject]) && (bStopCopy == NO)) {
    [btMainWindowStopQuitButton setTitle: @"Stop..."];
    [btMainWindowStopQuitButton setTag:1];
    bCopyInProgress = YES;
    __block NSError *eErrorMessage;
    sSourceFile = [sSourcePath stringByAppendingString:file];
    sDestinationFile = [sDestinationPath stringByAppendingString:file];
    // check if it's a directory & exists at destination
    BOOL isDirectory = NO;
    BOOL isFileExistingAtDestination = NO;
    __block BOOL isThereAnError = NO;
    [[NSFileManager defaultManager] fileExistsAtPath: [NSString stringWithFormat:@"%@/%@",sURL,file]
                                         isDirectory: &isDirectory];
    isFileExistingAtDestination = [[NSFileManager defaultManager] fileExistsAtPath: sDestinationFile];

    if (!isDirectory) {
        if (!isFileExistingAtDestination) {
            //                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            //                    if (![[NSFileManager defaultManager] copyItemAtPath:sSourceFile toPath:sDestinationFile error: &eErrorMessage]) {
            //                        NSLog(@"File Copy Error: %@", eErrorMessage);
            //                        isThereAnError = YES;
            //                    }
            //                });

            //[oqFileCopy addOperationWithBlock:^{
            dispatch_queue_t copyQueue = dispatch_queue_create("Copy File", NULL);
            dispatch_async(copyQueue, ^{
                if (![[NSFileManager defaultManager] copyItemAtPath:sSourceFile toPath:sDestinationFile error: &eErrorMessage]) {
                    NSLog(@"File Copy Error: %@", eErrorMessage);
                    isThereAnError = YES;
                }
            //[oqMain addOperationWithBlock:^{
                dispatch_async(dispatch_get_main_queue(), ^{
                    llFileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath: sDestinationFile error: Nil] fileSize];
                    [[[tvDialogueLabel textStorage] mutableString] setString:
                     [NSString stringWithFormat:@"%@\nCopied to: %@ (%qu bytes)", [[tvDialogueLabel textStorage] string], sDestinationFile, llFileSize]];
                    NSRange endPoint = NSMakeRange ([[tvDialogueLabel string] length], 0);
                    [tvDialogueLabel scrollRangeToVisible: endPoint];
                    llTotalFileSize = llTotalFileSize + llFileSize;
                });
            });
            //                NSLog(@"%@", sSourceFile);
            //                NSLog(@"%@", sDestinationFile);
        } else if (isFileExistingAtDestination) {
            [[[tvDialogueLabel textStorage] mutableString] setString:
             [NSString stringWithFormat:@"%@\nFile: %@ | Already Synced.", [[tvDialogueLabel textStorage] string], sDestinationFile]];
            NSRange endPoint = NSMakeRange ([[tvDialogueLabel string] length], 0);
            [tvDialogueLabel scrollRangeToVisible: endPoint];
        }
    }
    else if (isDirectory) {
        if (!isFileExistingAtDestination) {
            if (![[NSFileManager defaultManager] createDirectoryAtPath:sDestinationFile withIntermediateDirectories:YES attributes:nil error: &eErrorMessage]){
                NSLog(@"Directory Create Failed: %@", eErrorMessage);
                isThereAnError = YES;
            }
            [[[tvDialogueLabel textStorage] mutableString] setString:
             [NSString stringWithFormat:@"%@\nCreated Directory: %@", [[tvDialogueLabel textStorage] string], sDestinationFile]];
            NSRange endPoint = NSMakeRange ([[tvDialogueLabel string] length], 0);
            [tvDialogueLabel scrollRangeToVisible: endPoint];
            //                NSLog(@"%@", sSourceFile);
            //                NSLog(@"%@", sDestinationFile);
        } else if (isFileExistingAtDestination) {
            [[[tvDialogueLabel textStorage] mutableString] setString:
             [NSString stringWithFormat:@"%@\nDirectory: %@ | Already Exists.", [[tvDialogueLabel textStorage] string], sDestinationFile]];
            NSRange endPoint = NSMakeRange ([[tvDialogueLabel string] length], 0);
            [tvDialogueLabel scrollRangeToVisible: endPoint];
        }
        [self doSync: file];
    }

    if (isThereAnError) {
        NSLog(@"There was an error!");
        //[_wDialogue setTitle: @"Error while syncing..."];
        break;
    }
    //        NSLog(@"%@", @"==================================================");
}

}

4

2 回答 2

0

最简单的方法可能是从您的方法中删除所有块代码,并简单地调用 doSync: 使用 performSelectorInBackground:withObject:。例如:

[foo performSelectorInBackground:@selector(doSync:) withObject:myURL];
于 2013-09-12T02:02:35.937 回答
0

如果您使用的是 OSX 10.6 及更高版本,另一种简单的方法是将所有这些代码扔给 Grand Central Dispatch。while循环是需要在另一个线程上的,那是保持主线程的那个。通过将整个事物包装成一个dispatch_async(),您也将该while循环移动到不同的线程上。

- (void)doSync:(NSString *)sURL {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

        // your doSync code goes here
    });
}
于 2013-09-12T03:20:53.863 回答