Challenge: Removing an Image


#1

I’m sure there are plenty of different ways to do this. I did this using the new Assistant Editor skill I learned in this chapter.

First, I created a new UIBarButtonItem, and set its Identifier to “Trash” via the Attributes Inspector in my .xib file. I then used a Fixed Space Bar Button Item to move the trash can to the bottom right corner, opposite the camera (this was done somewhat for aesthetics, but also because the camera and trash button were awfully close, so I was trying to avoid accidentally hitting one when I wanted the other). From there, I just opened up the Assistant Editor and created a new action called clearImage. The code is below:

[code]- (IBAction)clearImage:(id)sender {

// Need to get the image from the possession
NSString *imageToKill = [possession imageKey];

// First check to see if there's an image
if (!imageToKill) {
    return;
}
else {
    // If there is an image, then delete it
    [[ImageStore defaultImageStore] deleteImageForKey:imageToKill];
}

}[/code]

Now, I am only running this in the Simulator, so I can’t actually test if this works or not (I was hoping the Simulator would let me use my built in iSight, but no such luck). If anyone uses this code, or implements a solution of their own, I’d love to see how it works out (or if this works at all)!


#2

Just one suggestion:
[ul]
invoke setImage:nil to remove the image from the view, otherwise it’s deleted but it’s not apparent:
NSString *imageToRemove = [possession imageKey];

// First check to see if there's an image
if (!imageToRemove) {
    return;
}
else {
    // If there is an image, then delete it
    [[ImageStore defaultImageStore] deleteImageForKey:imageToRemove];
    // refresh view
    [imageView setImage:nil];

[/ul]


#3

Ahh I see what you mean. Need to refresh the view so the user sees their deleted image actually was deleted. Otherwise they won’t see it until they navigate away and then back to the view. Thanks!


#4

I used the same idea (including the exact same button and spacing), but my method looks like:

- (IBAction)trashPicture:(id)sender {
    [[ImageStore defaultImageStore] deleteImageForKey:[possession imageKey]];
    [possession setImageKey:nil];
    [imageView setImage:nil];
}

I don’t check for the existence of an imageKey, because as I understand it, you can pass nil safely, and running this shows nothing on the console, but perhaps it’s not best practice. One thing I did do that’s not mentioned in other posts is that I set the image key in the possession explicitly to nil as well, but maybe this isn’t needed?

Thoughts?


#5

I also used the method the most of you used:

- (IBAction)brisiSliku:(id)sender { if ([possession imageKey]){ [[ImageStore defaultImageStore] deleteImageForKey:[possession imageKey]]; [imageView setImage:nil]; } }


#6

Perhaps you’re thinking of the Objective C feature where you can send a message to nil safely. As for taking nil as a parameter, that depends on the method. For example, the docs for NSDictionary notes under +dictionaryForObjectsAndKeys:

There’s no issue with passing nil as the key to -deleteImageForKey: because we (er, Joe :wink:) wrote the code for that method, and the first thing it does is return if the key is nil. (Good thing, too; the docs say an NSInvalidArgumentException is raised if the key is nil.)

Oh, and yes, it is a good thing to set possession’s imageKey to nil when the picture is deleted.


#7

As I was playing with the app, I realized that the code here may not be enough to delete the image.

What happens if you delete a possession that has an image attached to it? I think the image will still remain in the imageStore. It’s just a matter to make sure to delete any image if the possession is deleted, but first I wanted to see what’s in the imageStore at any point while the app is running.

I was trying to see the contents of the imageStore via debugging, but I couldn’t figure out how to do that, as I’m still a newbie.

Maybe I’ll try to add a label on the itemsViewController to give me a count of the imageStore images…

I welcome any thoughts, suggestions.


#8

Well, instead of a cumbersome label, I added a method on ImageStore to give me a count of the dictionary, and I added an NSLog to viewWillDisappear on ItemDetailViewController to show me that count (there’s probably a better spot for the NSLog but for testing, it will do).

This confirmed to me that deleting a possession didn’t remove an image from the imageStore.

So I added an import “ImageStore.h” to PossessionStore.h, and changed the removePossession: method on PossessionStore.m:

[code]- (void)removePossession:(Possession *)p
{
NSString *imageKey = [p imageKey];

if (imageKey) {
    [[ImageStore defaultImageStore] deleteImageForKey];
}

[allPossessions removeObjectIdenticalTo:p];

}
[/code]

I figured I didn’t need to set imageKey to nil, cause the object with the imageKey was about to be destroyed anyway.
My code for deleting the image with the button was pretty much like the others in here :slight_smile:


#9

In the viewWillAppear method you can also check to see if there is already an image, and if there is set the “enabled” property of the button to YES, otherwise set it to NO. That’s also pretty much just for aesthetics, but cool once you get it working :slight_smile:


#10

Tried the following:
Added additional trashButton to .xib beneath camera button.
While pressing alt I Drag&dropped a connection to it into instance variable section of ItemDetailViewController.h
this created IBOutlet UIBarButtonItem *buttonTrash;

In ItemDetailViewController.m

  • (void)viewWillAppear:(BOOL)animated
    {
    [super viewWillAppear];
    [nameField setText:[possession possessionName]];
    [serialNumberField setText:[possession serialNumber]];
    [valueField setText:[NSString stringWithFormat:@"%d", [possession valueInDollars]]];

    NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
    [dateFormatter setTimeStyle:NSDateFormatterNoStyle];

    [dateLabel setText:[dateFormatter stringFromDate:[possession dateCreated]]];
    [[self navigationItem] setTitle:[possession possessionName]];

    NSString *imageKey = [possession imageKey];
    if (imageKey) {
    UIImage *imageToDisplay = [[ImageStore defaultImageStore] imageForKey];
    [imageView setImage:imageToDisplay];
    [buttonTrash.customView setHidden:FALSE];
    } else {
    [imageView setImage:nil];
    [buttonTrash.customView setHidden:TRUE];
    }
    }

This one does nothing:
[buttonTrash.customView setHidden:TRUE];

What is wrong here?

btw: - (IBAction)removeImage:(id)sender; does work :slight_smile: