本文主要解决重启应用程序后,如何从沙盒中正确读取到沙盒中保存的图片并显示的问题。
沙盒的作用不再赘述。本文主要讲解一般程序开发中关于用户头像的操作问题。此方法可以延伸到其它类似的功能上——将一张图片存入沙盒,本次操作或者重启程序后,依然可以读取到这张图片。
为了优化流程及缩减数据库的体积,通常我们保存图片的做法是——将图片保存到后台(或沙盒)的某一个位置,然后将该图片存放位置的绝对路径保存到数据库中。
从iOS 7开始,苹果的沙盒机制有了改变:每一次重启程序后,读取沙盒的Documents目录时,Application下的子目录(类似于72E864E2-EA79-4FD3-A73F-8C5A00E7994D这种名称的文件夹)都是会被改变的,但是该子目录下的Documents、Library和tmp子目录及这三个子目录下的内容依然存在。这就相当于,已经保存的文件还是存在于沙盒里面,但是读取这些文件的路径随着每次重启程序都是变化的。
因此,如果将图片存入沙盒,将图片所在的绝对位置保存到数据库(比如保存在沙盒的一个plist文件)中,那么应用程序重启后,读取plsit文件中图片的保存路径,将无法获取到图片,因为图片的实际位置已经改变了!
那么,如何解决这个问题呢?其实很简单。既然沙盒中的Documents文件夹的路径是随着每次重启程序变化的,那么我们可以只在plist文件中存储图像的名称,在每次从plist文件中读取图片名称后,采用通常方法获取到保存图片的沙盒路径,然后将图片名称appending到这个路径下即可。
如下代码简单演示相关的操作。
1. 创建资源目录并创建一个plist文件
//Model.m文件中
- (void)getTheObjectFromTheFile : (NSString*)fileName {
NSString *filePath = [self getTheFilePathOfFile:fileName];
NSMutableDictionary *dataDic = [[NSMutableDictionary alloc]initWithContentsOfFile:filePath];
NSLog(@"dataDic = %@", dataDic);
[[NSNotificationCenter defaultCenter] postNotificationName:@"localPlistFileDic" object:dataDic];
}
- (void)writeTheObject : (NSString*)object forKey : (NSString*)key toTheFile : (NSString*)fileName {
NSString *filePath = [self getTheFilePathOfFile:fileName];
NSMutableDictionary *dataDic = [[NSMutableDictionary alloc]initWithContentsOfFile:filePath];
[dataDic setObject:object forKey:key];
NSLog(@"dataDic = %@", dataDic);
BOOL set = [dataDic writeToFile:filePath atomically:YES];
if(set) {
NSLog(@"写入成功");
[self getTheObjectFromTheFile:fileName];
}else {
NSLog(@"写入失败");
}
}
- (NSString*)getTheFilePathOfFile : (NSString*)fileName {
NSMutableDictionary *dataDic = [[NSMutableDictionary alloc]initWithCapacity:5];
[dataDic setObject:@"Default" forKey:@"userImage"];
//获取应用程序沙盒里面plist文件的路径
NSArray *doc = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [ doc objectAtIndex:0 ];
NSString *filePath=[docPath stringByAppendingPathComponent:[fileName stringByAppendingString:@".plist"]];
NSMutableDictionary *dd = [[NSMutableDictionary alloc]initWithContentsOfFile:filePath];
NSLog(@"dd = %@", dd);
if (dd == nil || dd == NULL || [dd count] == 0) {
BOOL set = [dataDic writeToFile:filePath atomically:YES];
if(set) {
NSLog(@"写入成功");
}else {
NSLog(@"写入失败");
}
}
return filePath;
}
2. 将图片保存到沙盒,并将图片名称保存到沙盒中对应的plist文件中
- (void)saveTheImageToTheSandboxAndTheImageNameToThePlistInTheSandbox {
//先创建一个fileManager,用于在Documents文件夹下创建一个文件夹,目的是将用户头像保存在这个文件夹下,便于管理。
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent: @"UserImageFile"];
// 在Documents文件夹下创建一个名为UserImageFile的目录
[fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
//将图像存入沙盒中
filePath = [filePath stringByAppendingPathComponent: [NSString stringWithFormat:@"%@.jpg", imageName]];
//下面的这个方法,我是将保存在ImageAssets中的某一张图片保存到刚才的路径下
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@.jpg", iamgeName]]];
BOOL result = [UIImagePNGRepresentation(imageView.image)writeToFile: filePath atomically:YES]; // 保存成功会返回YES
if(result) {
NSLog(@"保存成功");
[_model writeTheObject : [NSString stringWithFormat:@"%@.jpg", imageName] forKey : @"userImage" toTheFile : @"plistFileName"];
}else {
NSLog(@"保存失败");
}
}
3. 程序重启后,读取图片并显示
如上面的内容所讲,读取图片时,需要获取当前沙盒Documents的路径,并将plist中的图片名称appending到路径的后面,具体代码如下:
- (void) viewDidLoad {
//注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getLocalPlistFileDic:) name:@"localPlistFileDic" object:nil];
}
- (void)showTheImageFromSandbox {
[_model getTheObjectFromTheFile : @"plistFileName"];
UIImage *userImage = [UIImage imageWithContentsOfFile:_userImageFile];
}
//实现通知方法
- (void)getLocalPlistFileDic :(NSNotification*) notification {
NSDictionary *dic = [notification object];
_userImageFile = [dic objectForKey:@"userImage"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent: @"UserImageFile"];
_userImageFile = [filePath stringByAppendingPathComponent: _userImageFile];
}