我正在尝试使用Objective-C / XCode编写一个程序,该程序将一个目录(源目录)备份到另一个目录(dest目录)。
当我在本地计算机上的小目录上测试程序时,它按预期工作。但是当我尝试一个大型目录或网络上的任何东西时,该程序就会出现问题。我知道线程就是答案。鉴于以下代码,我可以说我已经摆弄了各种方法来做到这一点。任何人都可以帮忙吗?我似乎无法正常工作。 以下是有问题的代码/方法:
- (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(@"%@", @"==================================================");
}
}
答案 0 :(得分:0)
最简单的方法可能是从方法中删除所有块代码,然后只需调用doSync:using performSelectorInBackground:withObject:。例如:
[foo performSelectorInBackground:@selector(doSync:) withObject:myURL];
答案 1 :(得分: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
});
}