首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》18.5 通过NSData将数据写入文件

关灯直达底部

Homepwner虽然可以固化所有的BNRItem对象,但是并不会保存相关的图片。下面扩充BNRImageStore,实现功能:加入图片时将图片保存为文件;需要时再从文件载入图片。

BNRItem对象的图片应该保存至Documents目录。保存文件时,可以将BNRItem对象的itemKey属性(用户拍摄或选取图片时生成)作为图片文件的文件名。

打开BNRImageStore.m,在类扩展中加入以下方法声明。

- (NSString *)imagePathForKey:(NSString *)key;

在BNRImageStore.m中实现imagePathForKey:,根据传入的键创建相应的文件路径。

- (NSString *)imagePathForKey:(NSString *)key

{

NSArray *documentDirectories =

NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,

NSUserDomainMask,

YES);

NSString *documentDirectory = [documentDirectories firstObject];

return [documentDirectory stringByAppendingPathComponent:key];

}

为了保存图片,需要先将图片的数据按JPEG格式提取出来,然后拷贝至内存中的某块缓冲区。Foundation框架提供的NSData类可以创建、维护和释放内存缓冲区,所以无须使用malloc这类C函数。NSData对象可以保存一定字节数的二进制数据,下面通过NSData来保存图片数据。

修改BNRImageStore.m中的setImage:forKey:,获取图片路径并保存图片,代码如下:

- (void)setImage:(UIImage *)image forKey:(NSString *)key

{

self.dictionary[key] = image;

// 获取保存图片的全路径

NSString *imagePath = [self imagePathForKey:key];

// 从图片提取JPEG格式的数据

NSData *data = UIImageJPEGRepresentation(image, 0.5);

// 将JPEG格式的数据写入文件

[data writeToFile:imagePath atomically:YES];

}

UIImageJPEGRepresentation函数有两个实参,一个是UIImage对象,另一个是浮点数变量,代表压缩质量。压缩质量的值必须在0到1之间,1代表最高质量(不压缩)。该函数会返回一个NSData对象。

向某个NSData对象发送writeToFile:atomically:消息,可以将该对象中的数据写入指定的文件。writeToFile:atomically:的第一个实参负责指定文件路径。第二个实参atomically是一个布尔值,当atomically为YES时,NSData对象会先将数据写入某个临时文件,然后等写入操作成功后再将文件移至第一个实参所指定的路径,并覆盖已有的文件。这样,即使应用在写入文件的过程中崩溃,也不会损坏现有的数据。

需要注意的是,这种将数据写入文件的方式不是固化。虽然NSData对象自身也可以固化,但writeToFile:atomically:的工作原理是将NSData对象中的数据逐字节复制到文件中。

修改BNRImageStore.m中的deleteImageForKey:,在移除指定的UIImage对象后,删除相应的图片文件。

- (void)deleteImageForKey:(NSString *)key

{

if (!key) {

return;

}

[self.dictionary removeObjectForKey:key];

NSString *imagePath = [self imagePathForKey:key];

[[NSFileManager defaultManager] removeItemAtPath:imagePath

error:nil];

}

修改后的BNRImageStore对象会将所有的图片保存在各自的文件中。当ImageStore对象要返回某个BNRItem对象的图片时,就需要读取相应的文件。通过UIImage的类方法imageWithContentsOfFile:可以从指定的文件载入图片。

修改BNRImageStore.m中的imageForKey:,使BNRImageStore对象能够通过文件创建图片(如果BNRImageStore对象已经包含指定的图片,就直接返回该图片)。

- (UIImage *)imageForKey:(NSString *)key

{

return self.dictionary[key];

// 先尝试通过字典对象获取图片

UIImage *result = self.dictionary[key];

if (!result) {

NSString *imagePath = [self imagePathForKey:key];

// 通过文件创建UIImage对象

result = [UIImage imageWithContentsOfFile:imagePath];

// 如果能够通过文件创建图片,就将其放入缓存

if (result) {

self.dictionary[key] = result;

}

else {

NSLog(@“Error: unable to find %@”, [self imagePathForKey:key]);

}

}

return result;

}

构建并运行应用,为某个BNRItem对象拍摄一张照片,然后按下Home键。再次启动Homepwner,选中之前设置了照片的BNRItem对象,BNRDetailViewController对象的视图应该会显示所有已存的详细信息,包括之前拍摄的照片。

Homepwner会在用户拍摄照片后立刻将相应的图片存入文件,但是对于BNRItem对象中的其他详细信息,则会在应用进入后台运行状态时再保存。之所以要尽快地保存图片,是因为图片的尺寸很大,会占用太多的存储空间。