将照片加入BNRImageStore对象时,需要针对不同的照片使用不同的键,然后将这个键赋给相应的BNRItem对象。当BNRDetailViewController对象要从BNRImageStore对象载入照片时,需要先从BNRItem对象得到照片的键,然后通过BNRImageStore对象查找相应的照片。在BNRItem.h中为BNRItem类添加itemKey属性,用来保存照片的键,代码如下:
@property (nonatomic, readonly, strong) NSDate *dateCreated;
@property (nonatomic, copy) NSString *itemKey;
照片的键不能重复,否则无法通过BNRImageStore对象中的字典对象准确地保存对象。有很多种途径可以生成无重复的字符串(unique string),本节将使用Cocoa Touch提供的一种机制,这种机制可以生成唯一标识(UUID,也称为GUID)。每一个NSUUID类的对象都表示一个唯一的UUID。UUID是基于当前时间、计数器(counter)和硬件标识(通常为无线网卡的MAC地址)等数据计算生成的。如果使用字符串表示UUID,则示例如下:
4A73B5D2-A6F4-4B40-9F82-EA1E34C1DC04
在BNRDetailViewController.m顶部导入BNRImageStore.h,代码如下:
#import “BNRDetailViewController.h”
#import “BNRItem.h”
#import “BNRImageStore.h”
打开BNRItem.m,修改指定初始化方法,生成一个UUID并设置为itemKey:
- (instancetype)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber
{
// 调用父类的指定初始化方法
self = [super init];
// 父类的指定初始化方法是否成功创建了父类对象?
if (self) {
// 为对象变量设定初始值
_itemName = name;
_serialNumber = sNumber;
_valueInDollars = value;
// 设置_dateCreated的值为系统当前时间
_dateCreated = [[NSDate alloc] init];
// 创建一个NSUUID对象,然后获取其NSString类型的值
NSUUID *uuid = [[NSUUID alloc] init];
NSString *key = [uuid UUIDString];
_itemKey = key;
}
// 返回初始化后的对象的新地址
return self;
}
然后修改BNRDetailViewController.m中的imagePickerController:didFinish- PickingMediaWithInfo:,将UIImage对象存入BNRImageStore对象:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = info[UIImagePickerControllerOriginalImage];
// 以itemKey为键,将照片存入BNRImageStore对象
[[BNRImageStore sharedStore] setImage:image
forKey:self.item.itemKey];
imageView.image = image;
[self dismissViewControllerAnimated:YES completion:nil];
}
每当BNRDetailViewController获取到UIImage对象之后,都会将其存入BNRImageStore对象。BNRImageStore对象与BNRItem对象都保存了UIImage对象的键,随时可以通过键找到需要的UIImage对象。
类似地,在用户删除了某个BNRItem对象后,需要同时在BNRImageStore对象中删除对应的UIImage对象。在BNRDetailViewController.m顶部导入BNRImageStore.h,然后修改removeItem:方法,代码如下:
#import “BNRImageStore.h”
@implementation BNRItemStore
- (void)removeItem:(BNRItem *)item
{
NSString *key = item.itemKey;
[[BNRImageStore sharedStore] deleteImageForKey:key];
[self.privateItems removeObjectIdenticalTo:item];
}
读者也许会问,为什么不直接为BNRItem添加一个属性指向UIImage对象呢?这样不就可以直接处理UIImage对象了吗?虽然目前确实可以这么做,但是当本书第18章升级Homepwner,将BNRItem对象与UIImage对象存入文件系统时,就会遇到问题。
系统在创建了一个UIImage对象后,会将其保存在某块内存区域中,该内存区域有一个地址,称为内存地址。如果没有将UIImage对象从内存移动至文件系统,那么UIImage对象的内存地址将保持不变,确实可以通过添加一个UIImage属性,访问该属性指向的内存地址,找到对应的UIImage对象;但是,如果将UIImage对象存入文件系统,当应用重新启动时(第18章会详细介绍应用的生命周期),就需要将UIImage对象从文件系统载入内存,这时UIImage对象的内存地址会发生变化,无法使用之前的内存地址找到该对象。相反,如果使用键关联UIImage对象,BNRImageStore会先根据键在文件系统中找到对应的UIImage对象,然后将其载入内存,返回新的UIImage对象指针。因此,使用键可以正确地持久化保存UIImage对象。