I want to delete a Table View cell, but before that action happens I want to give the user an alertview. I got this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"Are you sure?"
delegate:self
cancelButtonTitle:#"NO"
otherButtonTitles:#"YES", nil];
[alert show];
[self.array removeObjectAtIndex:indexPath.row];//or something similar to this based on your data source array structure
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Nee"])
{
NSLog(#"Nothing to do here");
}
else if([title isEqualToString:#"Ja"])
{
NSLog(#"Delete the cell");
}
}
But now when I swipe to right on the cell and the delete button appears I got no AlertView. I only get the AlertView when I press on the delete button. When I press on the delete button the message appears but the cell is already been deleted.
How to make this work? So there is an AlertView when I swipe.
Regarding the sequence, everything is fine. commitEditingStyle will be called only when the delete button was pressed already. The point is that you are actually removing the object before the alert is responded to. Change it to this:
Add this to the .m file before #implementation:
#interface PutYourViewControllerClassNameHere
#property (strong, nonatomic) NSIndexPath *indexPathToBeDeleted;
#end
And then:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
self.indexPathToBeDeleted = indexPath;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"Are you sure?"
delegate:self
cancelButtonTitle:#"NO"
otherButtonTitles:#"YES", nil];
[alert show];
// do not delete it here. So far the alter has not even been shown yet. It will not been shown to the user before this current method is finished.
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// This method is invoked in response to the user's action. The altert view is about to disappear (or has been disappeard already - I am not sure)
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"NO"])
{
NSLog(#"Nothing to do here");
}
else if([title isEqualToString:#"YES"])
{
NSLog(#"Delete the cell");
[self.array removeObjectAtIndex:[self.indexPathToBeDeleted row]];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:self.indexPathToBeDeleted] withRowAnimation:UITableViewRowAnimationFade];
}
}
Edit: This should compile, despite minor syntax errors probably.
General assupmtion: You are dealing with one section only. At least only with one section within deletions are possible.
iOS 8 +
iOS 8 introduced UIAlertController. This allows you to write your delete and cancel code in completion blocks instead of in delegate methods (as per -clickedButtonAtIndex of the old UIAlertView).
Swift 3
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let alertController = UIAlertController(title: "Warning", message: "Are you sure?", preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: { (action) in
self.tableView.deleteRows(at: [indexPath], with: .fade)
})
alertController.addAction(deleteAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
}
Objective-C
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Warning" message:#"Are you sure?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:#"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}];
[alertController addAction:deleteAction];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(#"Don't do anything");
}];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
}
Youre calling the Alert when the deleting action is already taking place....
Put it in:
-(void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Waarschuwing!"
message:#"Weet je zeker dat je het vak: lalaal wilt verwijderen?"
delegate:self
cancelButtonTitle:#"Nee"
otherButtonTitles:#"Ja", nil];
[alert show];
}
That will call the alert when the cell is swiped and before the button is pressed.
iOS 9.0 and Swift 2.3
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let alertController = UIAlertController(title: "Warning!", message: "You're about to delete this stuff right meow.", preferredStyle: .Alert)
let delete = UIAlertAction(title: "Do it.", style: .Destructive, handler: { action in
tableView.beginUpdates()
//delete from your datasource!
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
tableView.endUpdates()
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel, handler: { action in
//this is optional, it makes the delete button go away on the cell
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
})
alertController.addAction(delete)
alertController.addAction(cancel)
presentViewController(alertController, animated: true, completion: nil)
}
}
Related
I have a tap and hold the event in the list (UITableView) of my application:
ViewDidLoad PlayerViewController.m:
UILongPressGestureRecognizer *agendarProg = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(agendarPrograma:)];
agendarProg.minimumPressDuration = 0.5; //segundos
agendarProg.delegate = self;
[self.tableView addGestureRecognizer:agendarProg];
function agendarPrograma in PlayerViewController.m:
-(void)agendarPrograma:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint ponto = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:ponto];
cell = [self.tableView cellForRowAtIndexPath:indexPath];
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
if (cell.imageAgendamento.hidden == true) {
cell.imageAgendamento.hidden = false;
NSString *horaPrograma = [ NSString stringWithFormat:#"%#",[[results objectAtIndex:indexPath.row] objectForKey:#"hora" ]];
[self addNotification:horaPrograma];
UIAlertView *alert1 = [[UIAlertView alloc]initWithTitle:#"Agendamento" message:#"Programa agendado" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[alert1 show];
[self performSelector:#selector(dismiss:) withObject:alert1 afterDelay:1.5];
} else {
cell.imageAgendamento.hidden = true;
[self deleteNotification];
UIAlertView *alert1 = [[UIAlertView alloc]initWithTitle:#"Agendamento" message:#"Agendamento cancelado" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[alert1 show];
[self performSelector:#selector(dismiss:) withObject:alert1 afterDelay:1.5];
}
} else {
return;
}
}
PROBLEM: when I use tap and hold him add the image on the line I chose but also add in others. I need it to add just where I'm using tap and hold. add in row choose but add other imagem in list random.
EXAMPLE: I used tap and hold in "Sorrindo pra vida" hidden image equal a false, but in "Musicas Marianas" the image show too
You can set multi selected of table to false and get correct cell by delegate tableview didSelectRow atIndexPath.
Just store indexPath as global, like _indexPath:
-(void)agendarPrograma:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint ponto = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:ponto];
_indexPath = indexPath;
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
[self.tableView reloadData];
} else {
return;
}
}
and in:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
you implement this:
if([indexPath compare:_indexPath] == NSOrderedSame) {
cell.imageAgendamento.hidden = NO;
}else{
cell.imageAgendamento.hidden = YES;
}
Hope this could help.
This question already has answers here:
Two Alert Views in One View Controller - buttonIndex Response
(4 answers)
Closed 7 years ago.
EDIT:
Problem Solved ==> Simply giving a tag solved the problem.
I have the following problem:
On a view I have two UIalertviews:
NSString *message = [NSString stringWithFormat:#"Users must enter this code to join the meeting: %#", meetingCode];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Meeting code"
message:message
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"Copy to clipboard", nil];
[alert show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == [alertView cancelButtonIndex])
{
NSLog(#"Code not copied");
}
else
{
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = meetingCode;
NSLog(#"Code copied");
}
}
and this one:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
AgendaModel* agenda = _meeting.agenda[indexPath.row] ;
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:agenda.id,#"id",agenda.name,#"name", nil];
NSString *message = [NSString stringWithFormat:#"Are you sure that you want to delete : %#?", agenda.name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:message
delegate:self
cancelButtonTitle:#"Close"
otherButtonTitles:#"Delete", nil];
[alert show];
NSString *delete_url = [NSString stringWithFormat:#"RestAgendas/delete.json"];
[_meeting.agenda removeObject:agenda];
[self.tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[JSONAPI getWithPath:delete_url andParams:dict completion:^(id json, JSONModelError *err) {
NSLog(#"%#", json);
}];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == [alertView cancelButtonIndex])
{
NSLog(#"Agenda Won't Be Deleted");
}
else
{
NSLog(#"Agenda Will Be Deleted");
}
}
Now is the problem that I got the error: Duplicate declaration of method 'alertView:clickedButtonAtIndex'
How can I fix this? I tried some stuff I found here but I still can't make it work. Can someone help me?
Yep, like you said, giving a tag allows you to have multiple UIAlertView in one single view.
Same goes for UIActionSheet or UIAlertController
for future reference, even though this is probably a duplicate, simply create your alert like usual and add
myAlert.tag = 123; //any number of your choice
and in alertView:clickedButtonAtIndex
you can find it using a switch or some if's
if (alertview.tag = 123){
// this is my alert
}else if(alertview.tag = 333){
// this is my other alert
}
For what it's worth, I suggest using else if and not just if to avoid the whole method to be read everytime, and order your if's by decreasing likeliness of being called.
Note you can also give tags to buttons, views, cells, labels, and just pretty much every outlet you can find.
I cannot figure out why I keep getting an EXC_BAD_ACCESS error on the line below in the action sheet method:
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:numberFinal]];
I added my code, but I just don't see why its being over released.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
number = [[results objectAtIndex:indexPath.row]objectForKey:#"phone"];
number = [number stringByReplacingOccurrencesOfString:#"-" withString:#""];
numberFinal = [NSString stringWithFormat:#"tel:%#",number];
//tel:1234567890
NSLog(#"NUMBER:%#",numberFinal);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIAlertView *alert2 = [[[UIAlertView alloc]initWithTitle:#"Call" message:#"Call This Person?" delegate:self cancelButtonTitle:#"NO" otherButtonTitles:#"YES", nil]autorelease];
alert2.tag = kAlertViewTwo;
[alert2 show];
// [alert2 release];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if(actionSheet.tag == kAlertViewOne) {
if (buttonIndex == 0)
{
}else{
}
}
else if(actionSheet.tag == kAlertViewTwo) {
if (buttonIndex == 0)
{
//ok button clicked - close alert
}
else
{
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:numberFinal]];
}
}
}
Try do an NSLog before the line and print numberFinal to see if it allocated ok.
Make sure your class is a UIAlertView Delegate
Try the same line of code in another function to see if it causes the same issue. It might be because you are accessing sharedApplication from within the UIAlertView click event.
Hope that helps :)
I have an UITableViewController, set up so that users can delete rows. This is my code for the handler of the delete action, and the delegate method for the UIAlertView:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"t" message:#"del?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Delete", nil];
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
if (buttonIndex != [alertView cancelButtonIndex]) {
//my code to delete from the data source is here. it works fine.
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationFade];
}
}
The problem is in that last line where it's supposed to actually delete the rows from the tableView. If I put that (and the code that deletes from the data source) in the first method instead of the UIAlertView stuff, it works fine.
What is the proper way of doing this?
The problem was that the UIIndexPath object was wrong inside that method! I guess it's because there is no row selected while the alert view is showing. So, I saved it before doing the UIAlertView code into a property of the view controller class, and retrieved it later in the second method, and it works fine.
I have added a bar button item in my tool bar and I implemented its functionality in the method given below. I am not able, however, to display a delete button in each row. How can I do this?
-(void)setEditing:(BOOL)editing
animated:(BOOL)animated
{
[super setEditing:editing
animated:animated];
[editButton setEnabled:!editing];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSString *selectedFile = (NSString*) [directoryContents objectAtIndex: indexPath.row];
NSString *selectedPath = [directoryPath stringByAppendingPathComponent:selectedFile];
BOOL canWrite = [[NSFileManager defaultManager] isWritableFileAtPath:selectedPath];
if(!canWrite)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"status"
message:#"path isnt writable"
delegate:nil
cancelButtonTitle:#"cancel"
otherButtonTitles:nil];
[alert show];
[alert release];
}
NSError *err = nil;
if(! [[NSFileManager defaultManager] removeItemAtPath:selectedPath error:&err])
{
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"status"
message:#"cannot delete"
delegate:nil
cancelButtonTitle:#"cancel"
otherButtonTitles:nil];
[alert1 show];
[alert1 release];
}
// Delete the row from the data source.
NSArray *deletedPaths = [NSArray arrayWithObject: indexPath];
[self loadDirectoryContents];
[self.tableview deleteRowsAtIndexPaths:deletedPaths withRowAnimation:YES];
}
}
The button on the toolbar will need to be connected to an interface action in the custom table view controller subclass. Define the action as follows -
- (IBAction)startEditing {
[self setEditing:YES animated:YES];
}
-(void)setEditing:(BOOL)editing
animated:(BOOL)animated
{
[super setEditing:editing
animated:animated];
[editButton setEnabled:!editing];
}
You will have to implement the delegate method tableView:editingStyleForRowAtIndexPath and return UITableViewCellEditingStyleDelete for the rows you wish to enable it.