2012-11-26 83 views
2

我無法使NSFileManager方法replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:在iOS 6中工作。在iOS 5上調用此方法並正常工作的應用程序在iOS 6上存在主要問題。在運行iOS 6.0以下版本的設備上不會出現此問題。如果應用程序是由Xcode在iOS模擬器中啓動的,則不會發生該問題。否則,這個問題似乎是普遍的。replaceItemAtURL:withItemAtURL:backupItemName:options:resultsItemURL:error:broken in iOS 6?

下面是測試代碼,我試圖執行:

NSError *error; 
NSFileManager *fileManager = [NSFileManager defaultManager]; 
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:@"test.txt"]; 
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"test.txt"]; 

// Create initial file in documents directory 
if (![fileManager fileExistsAtPath:destinationPath]) 
{ 
    BOOL fileCopied = [fileManager copyItemAtPath:sourcePath 
              toPath:destinationPath 
              error:&error]; 
    if (!fileCopied) 
     [[self statusLabel] setText:[NSString stringWithFormat:@"Creation Error:\n\n%@", 
            [error localizedDescription]]]; 
} 

// Replace file in documents directory with copy of file from app bundle 
if ([fileManager fileExistsAtPath:destinationPath]) 
{ 
    NSURL *destinationURL = [NSURL fileURLWithPath:destinationPath]; 
    BOOL fileReplaced = [fileManager replaceItemAtURL:destinationURL 
             withItemAtURL:[NSURL fileURLWithPath:sourcePath] 
             backupItemName:nil 
               options:0 
            resultingItemURL:&destinationURL 
               error:&error]; 
    if (!fileReplaced) 
     [[self statusLabel] setText:[NSString stringWithFormat:@"Replacement Error:\n\n%@", 
            [error localizedDescription]]]; 
    else 
     [[self statusLabel] setText:@"Successfully replaced file."]; 
} 

它創建的文件目錄中的文件,如果它不存在。然後它嘗試用文件夾中的文件副本替換文檔目錄中的文件。然後它會報告文件創建/替換的狀態。正如我之前所說的,如果它在iOS 5或更低版本上運行,或者如果它正在iOS Simulator中運行並且附加了Xcode,它將會取代它。但是,如果它在iOS 6設備或iOS Simulator上運行而沒有Xcode,則替換將失敗並返回錯誤。本地化的錯誤描述是The operation couldn’t be completed. (Cocoa error 512.)

用戶信息字典的錯誤是:

{ 
NSFileNewItemLocationKey = "file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Test.app/test.txt"; 
NSFileOriginalItemLocationKey = "file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Documents/test.txt"; 
NSURL = "file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Documents/test.txt"; 
NSUnderlyingError = "Error Domain=NSCocoaErrorDomain Code=513 \"The operation couldn\U2019t be completed. (Cocoa error 513.)\" UserInfo=0x1d58d350 {NSFilePath=/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Test.app/test.txt, NSURLUnsetValueKeysKey=<CFArray 0x1d58d180 [0x39b9d100]>{type = immutable, count = 2, values = (\n\t0 : <CFString 0x39b945b4 [0x39b9d100]>{contents = \"NSURLFileSecurityKey\"}\n\t1 : <CFString 0x39b943d4 [0x39b9d100]>{contents = \"NSURLCreationDateKey\"}\n)}, NSUnderlyingError=0x1d58d010 \"The operation couldn\U2019t be completed. Operation not permitted\", NSURL=file://localhost/var/mobile/Applications/487FBB9E-A2BD-4CF2-BB38-F36764623C2F/Test.app/test.txt}"; 
} 

我在App Store上的應用程序依賴於這種方法。實時應用程序繼續在iOS 5上沒有任何缺陷地工作,但在iOS 6中,由於方法失敗,它具有巨大的問題。有誰知道爲什麼這種方法失敗?

回答

8

NSFileManager方法replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:不是複製方法;這是一種移動方法。即,替換文件的拷貝並不替換該文件,而是替換文件本身。由於應用程序不應該能夠修改自己的包,所以上述代碼應該永遠不會在任何iOS版本中起作用。

要保留原子性,解決方案是先將替換文件的副本保存到臨時目錄,然後將該文件替換爲臨時目錄中的副本。

這裏是固定的測試代碼:

NSError *error; 
NSFileManager *fileManager = [NSFileManager defaultManager]; 
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 

NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt"]; 
NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:@"test.txt"]; 

// Create initial file in documents directory 
if (![fileManager fileExistsAtPath:destinationPath]) 
{ 
    BOOL fileCopied = [fileManager copyItemAtPath:sourcePath 
              toPath:destinationPath 
              error:&error]; 
    if (!fileCopied) 
     [[self statusLabel] setText:[NSString stringWithFormat:@"Creation Error:\n\n%@", [error localizedDescription]]]; 
} 

// Replace file in documents directory with copy of file from app bundle 
if ([fileManager fileExistsAtPath:destinationPath]) 
{ 
    // Create temporary file 
    NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.txt"]; 

    BOOL tempCopied = [fileManager copyItemAtPath:sourcePath 
              toPath:tempPath 
              error:&error]; 
    if (!tempCopied) 
     [[self statusLabel] setText:[NSString stringWithFormat:@"Temp Creation Error:\n\n%@", [error localizedDescription]]]; 

    // Replace file with temporary file 
    NSURL *destinationURL = [NSURL fileURLWithPath:destinationPath]; 

    BOOL fileReplaced = [fileManager replaceItemAtURL:destinationURL 
             withItemAtURL:[NSURL fileURLWithPath:tempPath] 
             backupItemName:nil 
               options:0 
            resultingItemURL:&destinationURL 
               error:&error]; 
    if (!fileReplaced) 
     [[self statusLabel] setText:[NSString stringWithFormat:@"Replacement Error:\n\n%@", [error localizedDescription]]]; 
    else 
     [[self statusLabel] setText:@"Successfully replaced file."]; 
}