First App Update, User Data Lost (was stored in Documents directory) First App Update, User Data Lost (was stored in Documents directory) ios ios

First App Update, User Data Lost (was stored in Documents directory)


Just to shed some more light on this for internet passer-bys. Yes, the OP answered his own question at the very end. You should never store absolute URLs for files in your documents directory and doing so may cause data loss. This is because when you update an app, by changing its version # in the .plist file, iOS creates a new directory for that app with a different hexadecimal name. Now your absolute URL is referencing the incorrect location and won't return the proper file.

You can see this on your own computer before you even deploy to a device by navigating to

~/Library/Application Support/iPhone Simulator/*ios_version*/Applications/

There you'll see folders with names like:

6AA4B05C-8A38-4469-B7BE-5EA7E9712510CB43C5F3-D720-49C3-87D4-EBE93FFD428B

Inside those folders will be the standard file system layout for iOS apps. i.e.

DocumentsLibrarytmpYourApp.app

By referencing the entire URL, you'll see something like,

~/Library/Application Support/iPhone Simulator/*ios_version*/Applications/6AA4B05C-8A38-4469-B7BE-5EA7E9712510/Documents/MyVeryImportantUserData.txt

However when you update the app the new URL that the app will try will be:

~/Library/Application Support/iPhone Simulator/*ios_version*/Applications/CB43C5F3-D720-49C3-87D4-EBE93FFD428B/Documents/MyVeryImportantUserData.txt

which is empty.

Instead you should always make a dynamic reference by only saving the filepath after you've gotten the documents directory filepath prefix.

/** Returns the path to the application's Documents directory. */- (NSString *)applicationDocumentsDirectory {    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];}

To the original poster, you could have saved your users lost data by issuing a new update where you modified your code to take the absolute url and trim everything through the documents portion of the string. Then you could prefix the filepath with the proper documents directory url and the app would have found the data.


Both the question poster and the first answer were helpful in clarifying what exactly was going on.

So building on their observations, I came to realize that there was (what appears to be) a renaming of the folders within the path that lead up to the Documents folder. This lead me to a solution where I'm saving only the fileNames of the files and creating a utility class for grabbing the current fullPath string of the fileName that had been saved and is now stored in the current Documents folder after the app updates:

#import "StringUtils.h"@implementation StringUtils+ (NSString *)getFullDocumentUrl:(NSString *)fileName{    return [NSString stringWithFormat:@"%@/%@",[self applicationDocumentsDirectory],fileName];}+ (NSString *)applicationDocumentsDirectory{    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];}@end


I ran into the same problem. Below is some example code to fix your filenames by iterating through the files in your documents directory and substituting out the filepath information while leaving the filenames. Before executing the last line to change the filenames, I would recommend using NSLog to make sure this is exactly what you want in your updatedName.

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);    NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory    NSFileManager *fm = [NSFileManager defaultManager];    NSArray *filenames = [fm contentsOfDirectoryAtPath:documentsPath error:nil];    //Match on the filepath leading up to docs directory    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^/\\S*Documents/"                                                                           options:NSRegularExpressionCaseInsensitive                                                                             error:nil];    for (NSString *fileName in filenames)    {        NSRange fullLength = NSMakeRange(0, [fileName length]);        //swap out the prepended directory structure with an empty string        NSString *updatedFileName = [regex stringByReplacingMatchesInString:fileName                                                                    options:0                                                                      range:fullLength                                                               withTemplate:@""];        NSString *currentName = [NSString stringWithFormat:@"%@/%@",documentsPath,fileName];        NSString *updatedName = [NSString stringWithFormat:@"%@/%@",documentsPath,updatedFileName];        [fm moveItemAtPath:currentName toPath:updatedName error:nil];    }