第一次应用程序更新,用户数据丢失(存储在Documents目录中)

我的第一个应用程序更新昨天刚刚上线,我收到了一个抱怨,说更新导致用户创build的数据(其中一些)消失。 我已经能够重现这个问题,但是不知道为什么。

在Documents目录中,我保存了一个关键文件,告诉我所有用户文件的“标题”及其文件名(完整path)。 然后,所有用户的文件也在Documents目录中。

更新发生时,密钥文件仍然存在(至less,我认为这是因为数据显示在应用程序的第一个屏幕 – 应用程序完全退出,并在更新后重新启动,对吧?),但是当用户尝试导航到实际的文件,没有数据和用户input的任何新的数据从不保存。

它的行为和debugging时一模一样,当我意外地使用一个无效的文件名时(不正确的字符) – 它从来没有保存过。 但随着更新,这些文件已被正确保存在旧版本,但在某种程度上在新版本中失败。

这是我的第一个应用程序和我的第一个更新,我在这里相当茫然。 我已经从现在的销售中拉出了应用程序(不知道你不能简单地回复到旧版本!),并且非常感谢关于在哪里/如何查找问题以及如何写一个好的更新,不会丢失数据。 (到目前为止,我所发现的只是“将数据保存到文档目录中”,这正是我已经在做的)。

我确实有原来的应用程序保存在自己的项目中,我可以回去再次工作。 当我开始进行更新时,我复制了整个目录,而且我怀疑这是否会成为问题? 我改变了保存所有XCode文件的目录名称,并使用了Project> Rename函数。 莫名其妙地有这个效果吗?

该应用程序(包括原始和更新)运行在4.2及以上版本,如果这很重要。

parsing度:

我相信我已经想出了这个问题。 就像我在问题开始时所说的那样,我将用户文件的完整path保存在我的密钥文件中。 显然,完整的path不能保证在更新后是相同的(我确定这是logging在某处,但我没有跑过去)。

因此,用户文件HAD被传送到更新的新文档目录,但是我正在以旧绝对path(即不在我的沙箱中)查找它们。

通过在应用程序的didFinishLaunching中放置一个循环来修复文件path的问题(我一直在本地寻找并且仍在工作),并将其截断为仅仅是文件path。 只要执行文件操作,就必须以编程方式find并添加文档path。

因为重新安装原始版本并不能解决用户的问题,所以对于我来说,对于我来说实在是件好事,因为没有办法在商店中恢复到以前的二进制文件,但我相信它至less有原来。 我希望有一种方法可以禁止更新,但仍然允许新购买(因为问题不会影响新的购买)。 虽然可能不是一个普通的情况,

只是为了让互联网路人更多地了解这一点。 是的,OP最后回答了他自己的问题。 您绝对不应该在您的文档目录中存储文件的绝对URL,否则可能会导致数据丢失 。 这是因为在更新应用程序时,通过更改.plist文件中的版本号,iOS会为该应用程序使用不同的hex名称创build一个新目录。 现在,您的绝对url引用了错误的位置,并且不会返回正确的文件。

您甚至可以在您通过导航到部署到设备之前,在自己的计算机上看到此信息

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

你会看到名字如下的文件夹:

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

这些文件夹内将是iOS应用程序的标准文件系统布局。 即

文档库tmp YourApp.app

通过引用整个URL,你会看到类似的东西,

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

但是,当您更新应用程序时,应用程序将尝试的新URL将是:

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

这是空的。

相反,您应该始终在获取文档目录文件path前缀后仅保存文件path来进行dynamic引用。

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

对于原始海报,您可以通过发布新的更新来保存用户丢失的数据,在此处修改代码以获取绝对URL并通过string的文档部分修剪所有内容。 然后你可以在文件path前加适当的文档目录url,应用程序就可以find这些数据。

问题海报和第一个答案都有助于澄清究竟发生了什么。

因此,根据他们的观察,我意识到有(似乎是)重命名文件夹的path内的文件夹。 这使我得到一个解决scheme,我只保存文件的文件名,并创build一个实用工具类来抓取已保存的文件名的当前 fullPathstring,并在应用程序更新后保存在当前的 Documents文件夹中:

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

我遇到了同样的问题。 以下是一些示例代码,通过遍历文档目录中的文件并在保留文件名时replace文件path信息来修复文件名。 在执行最后一行来更改文件名之前,我build议使用NSLog来确保这正是你想要在你的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]; }