iPhone 升级时保存的数据被删除?
我在应用程序商店中有一个应用程序,刚刚收到用户的一条消息,告诉我在升级到该应用程序的新版本后,他们保存的数据全部消失了。
是否有一种明显错误的方式在 iPhone 上保存数据,导致应用程序升级到新版本时会导致数据丢失?
这是我用来加载和加载的代码save,在开发机器上运行良好。这是错误的做法吗?
- (bool) saveData:(NSData*) data toFile:(NSString*) filename
{
NSError* error;
NSFileManager *fileMgr = [[[NSFileManager alloc] init] autorelease];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString* filePath = [docsDir stringByAppendingPathComponent:filename];
NSString* validMarkerPath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".val"]];
NSString* backupPath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".bak"]];
// If the file exists and is marke valid, copy it over the backup.
if([fileMgr fileExistsAtPath:filePath] && [fileMgr fileExistsAtPath:validMarkerPath])
{
if([fileMgr fileExistsAtPath:backupPath])
{
if(![fileMgr removeItemAtPath:backupPath error:&error])
{
NSLog(@"Error: SafeFileManager: Could not remove backup file %@: %@", backupPath, [error localizedDescription]);
}
}
if(![fileMgr moveItemAtPath:filePath toPath:backupPath error:&error])
{
NSLog(@"Error: SafeFileManager: Could not move %@ to %@: %@", filePath, backupPath, [error localizedDescription]);
}
}
// Remove the "valid" marker file, if present.
if([fileMgr fileExistsAtPath:validMarkerPath])
{
if(![fileMgr removeItemAtPath:validMarkerPath error:&error])
{
NSLog(@"Error: SafeFileManager: Could not remove validation file %@: %@", validMarkerPath, [error localizedDescription]);
}
}
// Save the new file.
if(![data writeToFile:filePath options:NSAtomicWrite error:&error])
{
NSLog(@"Error: SafeFileManager: Could not save to %@: %@", filePath, [error localizedDescription]);
return NO;
}
// If we succeeded, save the "valid" marker file.
NSData* markerData = [NSData dataWithBytes:"0" length:1];
if(![markerData writeToFile:validMarkerPath options:NSAtomicWrite error:&error])
{
NSLog(@"Error: SafeFileManager: Could not save validation file %@: %@", validMarkerPath, [error localizedDescription]);
return NO;
}
return YES;
}
- (NSData*) loadDataFromFile:(NSString*) filename
{
NSError* error;
NSFileManager *fileMgr = [[[NSFileManager alloc] init] autorelease];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString* filePath = [docsDir stringByAppendingPathComponent:filename];
NSString* validMarkerPath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".val"]];
// If the file isn't valid, we'll try to load the backup.
if(![fileMgr fileExistsAtPath:validMarkerPath])
{
filePath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".bak"]];
}
NSData* data = nil;
@try
{
data = [NSData dataWithContentsOfFile:filePath options:NSUncachedRead error:&error];
if(nil == data)
{
NSLog(@"Error: SafeFileManager: Could not load from %@: %@", filePath, [error localizedDescription]);
}
}
@catch (NSException * e)
{
NSLog(@"Error: SafeFileManager: Could not load from %@: %@", filePath, [e description]);
data = nil;
}
return data;
}
I have an app in the app store, and just got a message from a user telling me that upon upgrading to a newer version of the app, their saved data all disappeared.
Is there a distinctly wrong way to save data on the iphone that would cause data loss upon upgrading the app to a new version?
Here is the code I'm using to load & save, which works fine on development machines. Is this the wrong way to do it?
- (bool) saveData:(NSData*) data toFile:(NSString*) filename
{
NSError* error;
NSFileManager *fileMgr = [[[NSFileManager alloc] init] autorelease];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString* filePath = [docsDir stringByAppendingPathComponent:filename];
NSString* validMarkerPath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".val"]];
NSString* backupPath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".bak"]];
// If the file exists and is marke valid, copy it over the backup.
if([fileMgr fileExistsAtPath:filePath] && [fileMgr fileExistsAtPath:validMarkerPath])
{
if([fileMgr fileExistsAtPath:backupPath])
{
if(![fileMgr removeItemAtPath:backupPath error:&error])
{
NSLog(@"Error: SafeFileManager: Could not remove backup file %@: %@", backupPath, [error localizedDescription]);
}
}
if(![fileMgr moveItemAtPath:filePath toPath:backupPath error:&error])
{
NSLog(@"Error: SafeFileManager: Could not move %@ to %@: %@", filePath, backupPath, [error localizedDescription]);
}
}
// Remove the "valid" marker file, if present.
if([fileMgr fileExistsAtPath:validMarkerPath])
{
if(![fileMgr removeItemAtPath:validMarkerPath error:&error])
{
NSLog(@"Error: SafeFileManager: Could not remove validation file %@: %@", validMarkerPath, [error localizedDescription]);
}
}
// Save the new file.
if(![data writeToFile:filePath options:NSAtomicWrite error:&error])
{
NSLog(@"Error: SafeFileManager: Could not save to %@: %@", filePath, [error localizedDescription]);
return NO;
}
// If we succeeded, save the "valid" marker file.
NSData* markerData = [NSData dataWithBytes:"0" length:1];
if(![markerData writeToFile:validMarkerPath options:NSAtomicWrite error:&error])
{
NSLog(@"Error: SafeFileManager: Could not save validation file %@: %@", validMarkerPath, [error localizedDescription]);
return NO;
}
return YES;
}
- (NSData*) loadDataFromFile:(NSString*) filename
{
NSError* error;
NSFileManager *fileMgr = [[[NSFileManager alloc] init] autorelease];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString* filePath = [docsDir stringByAppendingPathComponent:filename];
NSString* validMarkerPath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".val"]];
// If the file isn't valid, we'll try to load the backup.
if(![fileMgr fileExistsAtPath:validMarkerPath])
{
filePath = [docsDir stringByAppendingPathComponent:[filename stringByAppendingString:@".bak"]];
}
NSData* data = nil;
@try
{
data = [NSData dataWithContentsOfFile:filePath options:NSUncachedRead error:&error];
if(nil == data)
{
NSLog(@"Error: SafeFileManager: Could not load from %@: %@", filePath, [error localizedDescription]);
}
}
@catch (NSException * e)
{
NSLog(@"Error: SafeFileManager: Could not load from %@: %@", filePath, [e description]);
data = nil;
}
return data;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为了回答我自己的问题,这段代码确实有一个写入漏洞,其中备份文件和标记文件被删除,这会导致加载失败。
我现在选择了一种更简单(如果不是更暴力)的方法,即简单地保存文件,然后保存备份。加载时,它会尝试主文件,如果发生任何错误,它会使用备份文件尝试相同的加载例程。
To answer my own question, this code does have a write hole where the backup file and marker file are deleted, which would cause the load to fail.
I've now opted for a simpler, if not more brute-force approach of simply saving the file, then saving a backup. On load, it tries the main file, and if any error occurs whatsoever, it attempts the same load routine using the backup file.