I'm working on an app that behaves like a photo gallery, and I'm implementing the option to have the user delete photos from their gallery. To accomplish this, I decided to place an invisible button over each picture. When the user hits an "Edit" button, the hidden delete buttons over each picture become active. I'm using the same IBOutlet over each of the hidden buttons for simplicity, and I've tagged each button appropriately in Interface Builder. When the user taps the button over the picture, an alert view appears asking if they really want to delete it. If they click yes, I call removeObjectAtIndex. Here is the code I'm using:
- (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;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(@"User Clicked Yes.");
[self.array removeObjectAtIndex: alertView.tag];
}
[self.user setObject:array forKey:@"images"];
}
The issue here is that when I click "Yes" in the alert view, nothing happens. However, if I tap on the image and click "Yes" a second time, the app crashes, and the debug states: Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray removeObjectAtIndex:]: index (0) beyond bounds (0)' So, I'm not sure where to go from here, I'm still very new to programming and everything looks correct to me. Any help is much appreciated, thanks!
Here is how I add them into the array:
////start of saving////
- (void)viewWillAppear:(BOOL)animated
{
self.user = [NSUserDefaults standardUserDefaults];
self.array = [[self.user objectForKey:@"images"]mutableCopy];
while(self.array == nil)
{
[self.user setObject:[NSMutableArray arrayWithObject:@""] forKey:@"images"];
self.array = [[self.user objectForKey:@"images"]mutableCopy];
NSLog(@"%@",@"attempting to create an array to store the images in");
}
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(@"Image on didenterbackground: %@", imageView);
self.array = [NSMutableArray arrayWithObject:[NSData dataWithData:UIImagePNGRepresentation(imageView.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView2.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView3.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView4.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(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 = [[UIImage alloc] initWithData:[self.array objectAtIndex:0]];
imageView2.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:1]];
imageView3.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:2]];
imageView4.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:3]];
imageView5.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:4]];
imageView6.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:5]];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
backToGalleryButton.hidden = YES;
tapToDeleteLabel.hidden = YES;
deleteButton1.hidden = YES;
[super viewDidLoad];
}
- (void)viewDidUnload
{
self.user = nil;
}
////end of saving
///// shows the hidden and invisible "delete" button over each photo.
- (IBAction)editButtonPressed:(id)sender {
grabButton.hidden = YES;
editButton.hidden = YES;
backToGalleryButton.hidden = NO;
tapToDeleteLabel.hidden = NO;
deleteButton1.hidden = NO;
}
- (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;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(@"User Clicked Yes.");
NSLog(@"Array: %@, index: %d", self.array, alertView.tag);
[self.array removeObjectAtIndex: alertView.tag];
}
[self.user setObject:array forKey:@"images"];
}
@end
EDIT: This is the code I use to put the objects into the UIImageView from the users camera roll:
- (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;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView4.image == nil) {
imageView4.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
}
When I added NSLog(@"Array: %@, index: %d", self.array, alertView.tag); just before removeAtIndex the console says 2012-04-03 18:39:39.066 AppName[1631:f803] Array: (null), index: 0. Could that be the cause? I'm not sure why it would be, I think the code looks fine.
NSLog(@"Array: %@, index: %d", self.array, alertView.tag);
Phillip Mills 2012-04-03 23:50
[self.user setObject:array forKey:@"images"];
would of done the trick, how else could I refresh the screen - Henry F 2012-04-04 00:41
viewDidLoad
. Don't you think that logic needs to be repeated somehow - Hot Licks 2012-04-04 02:56
There are many oddities with this code but I think the problem is that you are not calling super on your viewwillappear and viewdidload functions. I would get rid of your viewWillAppear method as it serves no purpose.
[super viewDidLoad]
in viewDidLoad. However, the issue is still occurring. When I added NSLog(@"Array: %@, index: %d", self.array, alertView.tag);
just before removeAtIndex the console says 2012-04-03 18:39:39.066 AppName[1631:f803] Array: (null), index: 0. Could that be the cause? I'm not sure why it would be, I think the code looks fine - Henry F 2012-04-04 00:38
alertView.tag.image = nil;
, but that is obviously causing an error. I really need to go buy an Objective-C book, the books I've previously read do not cover any of this lol - Henry F 2012-04-04 02:46
Removing the image from the array is not the only step you have to take. Your code is correct for removing the image from the array, which is why you get image out of bounds the second time, but you also need to remove the image from the UI so the user can no longer delete an image that is not there.