When an image is added to the store, it will be put into a dictionary under a unique key, and the associated BNRItem object will be given that key. When the BNRDetailViewController wants an image from the store, it will ask its item for the key and search the dictionary for the image. Add a property to BNRItem.h to store the key.
@property (nonatomic, readonly, strong) NSDate *dateCreated; @property (nonatomic, copy) NSString *itemKey;
The image keys need to be unique in order for your dictionary to work. While there are many ways to hack together a unique string, you are going to use the Cocoa Touch mechanism for creating universally unique identifiers (UUIDs), also known as globally unique identifiers (GUIDs). Objects of type NSUUID represent a UUID and are generated using the time, a counter, and a hardware identifier, which is usually the MAC address of the WiFi card. When represented as a string, UUIDs look something like this:
4A73B5D2-A6F4-4B40-9F82-EA1E34C1DC04
Import BNRImageStore.h at the top of BNRDetailViewController.m.
#import "BNRDetailViewController.h" #import "BNRItem.h" #import "BNRImageStore.h"
In BNRItem.m, modify the designated initializer to generate a UUID and set it as the itemKey.
- (instancetype)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber { // Call the superclass's designated initializer self = [super init]; // Did the superclass's designated initializer succeed? if (self) { // Give the instance variables initial values _itemName = name; _serialNumber = sNumber; _valueInDollars = value; // set _dateCreated to the current date and time _dateCreated = [[NSDate alloc] init]; // Create an NSUUID object - and get its string representation NSUUID *uuid = [[NSUUID alloc] init]; NSString *key = [uuid UUIDString]; _itemKey = key; } // Return the address of the newly initialized object return self; }
Then, in BNRDetailViewController.m, update imagePickerController:didFinishPickingMediaWithInfo: to store the image in the BNRImageStore.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { UIImage *image = info[UIImagePickerControllerOriginalImage]; // Store the image in the BNRImageStore for this key [[BNRImageStore sharedStore] setImage:image forKey:self.item.itemKey]; imageView.image = image; [self dismissViewControllerAnimated:YES completion:nil]; }
Each time an image is captured, it will be added to the store. Both the BNRImageStore and the BNRItem will know the key for the image, so both will be able to access it as needed.
Similarly, when an item is deleted, you need to delete its image from the image store. At the top of BNRItemStore.m, import the header for the BNRImageStore and add the following code to removeItem:.
#import "BNRImageStore.h" @implementation BNRItemStore - (void)removeItem:(BNRItem *)item { NSString *key = item.itemKey; [[BNRImageStore sharedStore] deleteImageForKey:key]; [self.privateItems removeObjectIdenticalTo:item]; }
You might be thinking, “Why not give the BNRItem a pointer to the image? After all, isn’t a pointer to the image a more direct way of referring to the image?” While this is correct, you must consider what happens when you begin saving the items and their images to the filesystem in Chapter 18.
When a UIImage is first created, it exists in memory at a specific address. A pointer holds onto this address so you can refer to the image again. The next time the application launches, however, the image will not be at the same address in memory, so you cannot use the same pointer to access it. Instead, the key will be used to name the image file on the filesystem and each BNRItem will hang on to its key. When you want to load the image back into memory, the BNRImageStore will use the itemKey of a BNRItem to find the image file on the filesystem, load it into memory, and return a pointer to the new UIImage instance. Therefore, the key is a persistent way of referring to an image.