Henry F
Henry F

Reputation: 4980

Saving Images In iOS

I have an app that behaves like a photo gallery. I'm implementing the ability for the user to delete the photos, by placing an invisible button over each UIImageView, and calling removeObject when they tap on the button. This code is working great, but its dependent upon tags. I need to tag every UIImageView / UIButton in interface builder in order for this to work. So, I'm now trying to save the images in a way that my tags will still work, which excludes using NSData.

So I'm totally lost on what to do right now. I'm very, very new to programming and am shocked that I even made it this far. Any help or advice on what or how to edit my code to make this work is much appreciated, thanks!

Here is my entire file just for reference:

- (IBAction)grabImage {
    self.imgPicker = [[UIImagePickerController alloc] init];
    self.imgPicker.delegate = self;
    self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        _popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
        [_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    } 

    else {
        [self presentModalViewController:imgPicker animated:YES];
    }
    [self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
    if (imageView.image == nil) {
        imageView.image = img;

        [self.array addObject:imageView.image];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;

    }

    if (imageView2.image == nil) {
        imageView2.image = img;
        NSLog(@"The image is a %@", imageView);
        [self.array addObject:imageView2.image];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
    }

    if (imageView3.image == nil) {
        imageView3.image = img;

        [self.array addObject:imageView3.image];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
    }

    if (imageView4.image == nil) {
        imageView4.image = img;

        [self.array addObject:imageView4.image];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
    }
    if (imageView5.image == nil) {
        imageView5.image = img;

        [self.array addObject:imageView5.image];

        [picker dismissModalViewControllerAnimated:YES];
        [self.popover dismissPopoverAnimated:YES];
        return;
    }

- (void)applicationDidEnterBackground:(UIApplication*)application {
    NSLog(@"Image on didenterbackground: %@", imageView);

    [self.array addObject:imageView.image];
    [self.array addObject:imageView2.image];
    [self.array addObject:imageView3.image];
    [self.array addObject:imageView4.image];
    [self.array addObject:imageView5.image];

    [self.user setObject:self.array forKey:@"images"];
    [user synchronize];

}

- (void)viewDidLoad
{
    self.user = [NSUserDefaults standardUserDefaults];
    NSLog(@"It is %@", self.user);
    self.array = [[self.user objectForKey:@"images"]mutableCopy];
    imageView.image = [[self.array objectAtIndex:0] copy];
    imageView2.image = [[self.array objectAtIndex:1] copy];
    imageView3.image = [[self.array objectAtIndex:2] copy];
    imageView4.image = [[self.array objectAtIndex:3] copy];
    imageView5.image = [[self.array objectAtIndex:4] copy];



    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:app];

    [super viewDidLoad];

}


// This is when the user taps on the image to delete it.
- (IBAction)deleteButtonPressed:(id)sender {
    NSLog(@"Sender is %@", sender);
    UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:@"Delete"
                                                              message:@"Are you sure you want to delete this photo?"
                                                             delegate:self
                                                    cancelButtonTitle:@"No"
                                                    otherButtonTitles:@"Yes", nil];
    [deleteAlertView show];

    int imageIndex = ((UIButton *)sender).tag;
    deleteAlertView.tag = imageIndex;
}

- (UIImageView *)viewForTag:(NSInteger)tag {
    UIImageView *found = nil;
    for (UIImageView *view in self.array) {
        if (tag == view.tag) {
            found = view;
            break;
        }
    }
    return found;
}

- (void)alertView: (UIAlertView *) alertView 
clickedButtonAtIndex: (NSInteger) buttonIndex
{


    if (buttonIndex != [alertView cancelButtonIndex]) {
        NSLog(@"User Clicked Yes. Deleting index %d of %d", alertView.tag, [array count]);
        NSLog(@"The tag is %i", alertView.tag);

        UIImageView *view = [self viewForTag:alertView.tag];
        if (view) {
            [self.array removeObject:view];
        }

        NSLog(@"After deleting item, array count  = %d", [array count]);
        NSLog(@"Returned view is :%@, in view: %@", [self.view viewWithTag:alertView.tag], self.view);
        ((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil;
    }

    [self.user setObject:self.array forKey:@"images"];
}

@end

Upvotes: 1

Views: 1027

Answers (2)

Jody Hagins
Jody Hagins

Reputation: 28409

It seems you are using the tag just so you can identify which image view is being selected. You have an "invisible" button on top of each image? Is that right? I assume that is so you can handle a tap, which selects the image that is showing through the button?

There are lots of ways to do it, but a simple solution is to just recognize the tap, and "find" the image view underneath that tap. Drop a UITapGestureRecognizer onto your controller from within the storyboard. Ctrl-drag it into the code for your controller, and it will create an action method. Fill it in something like this...

  - (IBAction)tapGesture:(UITapGestureRecognizer*)gesture
  {
    CGPoint tapLocation = [gesture locationInView: self.galleryView];
    for (UIImageView *imageView in self.galleryView.subviews) {
      if (CGRectContainsPoint(imageView.frame, tapLocation)) {
        // This is the imageView that was tapped on!
        // Do whatever you want with it now that you found it.
      }
    }
  }

Upvotes: 1

Cowirrie
Cowirrie

Reputation: 7226

The previous comment is accurate; please think about how you're going to scale this up.

That said, you'll need to store and load images in some way, and that will always mean converting your UIImage objects to NSData. This applies whether you store them in NSUserDefaults, in files or in Core Data.

UIImage supports NSCoding, so you could use that. Read about how to use it, since you'll need it eventually. Or, if you know you'll always want to use PNG or JPEG formats, there are the functions UIImagePNGRepresentation(UIImage *image) and UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality). To convert the NSData objects back to UIImage, use [UIImage imageWithData:NSData*] Here's what you could have in applicationDidEnterBackground:

NSMutableArray *dataArray = [NSMutableArray array];
[dataArray addObject:UIImagePNGRepresentation(imageView.image)];
[dataArray addObject:UIImagePNGRepresentation(imageView2.image)];
[dataArray addObject:UIImagePNGRepresentation(imageView3.image)];
[self.user setObject:dataArray forKey:@"images"];
[self.user synchronize];

Then, to retrieve these during viewDidLoad:

[self.array removeAllObjects];
NSArray *dataArray = [self.user objectForKey:@"images"];
for (NSData *imageData in dataArray)
    [self.array addObject:[UIImage imageWithData:imageData]];

This will solve your immediate problem, but please don't consider it a permanent solution. Consider:

  1. Store your images in files or Core Data, as NSUserDefaults is not supposed to have large amounts of content.
  2. Use a UITableView to display the images, so you can have an arbitrary number instead of hard-coding for three.
  3. If UITableView doesn't have the layout you need, create a custom UIView subclass that displays an array of images and responds to taps appropriately.
  4. Make sure your application can detect all the ways it may be suspended or shut down. You may not always get the ApplicationDidEnterBackground notification, or you may not have time to save all your data after it happens. If you have multiple UIViewControllers, this one may be unloaded without the application itself receiving notifications.

Upvotes: 1

Related Questions