UIAlertAction handler is not called
Asked Answered
M

4

12

I have a UITableView and in the delegate (view controller), I have implemented the function

    tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)

I then test for the editing style

    if editingStyle == UITableViewCellEditingStyle.Delete {
        // do deleting stuff here
    }

As part of the delete, I am requesting confirmation from the user, if they select "yes", the item related to the row will be deleted, if they select no, I reset the editing style.

  var alert = UIAlertController(title: "Delete Item", message: "Are you sure you want to delete the selected item?", preferredStyle: UIAlertControllerStyle.Alert)

  //delete
  alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Destructive, handler: { (action: UIAlertAction!) -> Void in
      println("Yes action was selected")
      //delete my object and remove from the table
  }))

  //cancel
  alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (action: UIAlertAction!) -> Void in
      //reset editing
      println("Cancel action was selected")
      self.tableView.setEditing(false, animated: true)
  }))

  if self.presentedViewController == nil {
      presentViewController(alert, animated: true, completion: nil)
  }

The problem I appear to have is that neither completion handler is being called. I've used this format elsewhere with no issues.

The alert appears with the title, message and the buttons "Cancel" and "Yes". If I tap on either, nothing happens. The alert is dismissed and there are is no console output for the println statements and there is definitely nothing else happening. My delete code isn't executed for "Yes" and the editing reset isn't called for "cancel".

I have this same setup on other tableviews within the application and they work as expected.

This is in a view controller that has been presented modally from another view controller (if that has any bearing). I'm not getting any errors about any other presenting going on (hence the if self.presentedViewController == nil block).

I've obviously gone wrong somewhere, but at the moment I just can't see where. Any ideas?

IOS version being used in 8.4. Target is iPad.

Mouse answered 29/7, 2015 at 9:38 Comment(3)
By the way, just to mention that the delete stuff works. If I don't bother trying to prompt, my delete code works as expected. I just don't see what I've done wrong with the the UIAlertController and UIAlertActions.Mouse
I use your code and it works perfectly.Siccative
Yeah, it works perfectly in other areas of my app too - hence the confusion as to why it wouldn't work in this instanceMouse
C
7

I had the same issue and I found that I override the dismiss func:

override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    super.dismiss(animated: true, completion: nil)
}

the UIAlertController is using the completion block to pass data when you pass nil the action doesn't call at all.

When you override the dismiss func you need to pass the completion parameter

override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    super.dismiss(animated: true, completion: completion)
}

hope I help

Curt answered 21/1, 2018 at 14:42 Comment(1)
you my man! Make sure you call completion for swizzled methods too in case u run your own block thereMasochism
C
5

Check your ViewController is a childViewController of navigation. And if the navigation override:

(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^) (void))completion;

Your must sure call super dismissViewControllerAnimated:flag completion:completion.

And ensure parameter completion can not pass nil. UIAlertController will call this method (I confused that too). I log out the caller is UIAlertController _dismissAnimated:triggeringAction:triggeredByPopoverDimmingView: (confused again).

It work for me. I hope it work for your too.

Candice answered 17/1, 2017 at 6:0 Comment(1)
This has saved me from pulling my hair roots out. Thanks!Incorporator
M
0

you can check if this is working

    alert.addAction(UIAlertAction(title: "cancel", style: UIAlertActionStyle.Cancel, handler: { action in
        switch action.style{
        case .Default:
            println("default")

        case .Cancel:
            println("cancel")

        case .Destructive:
            println("destructive")
        }
    }))
Minnaminnaminnie answered 29/7, 2015 at 9:57 Comment(3)
No, that doesn't work. The handler isn't called. The alert appears, the "cancel" action appears on the alert. Tapping cancel - the alert is dismissed, the handler is not called. Same as above.Mouse
so "cancel" is not printed? nor your breakpoint is being called inside the handler?Minnaminnaminnie
That is exactly what is happening. I can't see why the handler isn't called. For the time being, I'm just going with carrying out the delete without prompting the user. I just can't figure it out. I'm using the same code elsewhere for similar prompts in the same application, even for deletions in other tableviews. I just can't see what is different here. I've even pasted the same code from other areas and just changed the text of the main alert message, with just a println statement in the handler. The handler just isn't called.Mouse
S
0

This question is rather old but I ran into same trouble today.

The point is you're using iPad so you must present it in popover

if UIDevice.current.userInterfaceIdiom == .pad{
  alert.modalPresentationStyle = .popover
  let pp = ac.popoverPresentationController
  pp?.sourceView = sender as? UIView // or pp?.sourceRect = <some rect...>
  present(alert, animated: true, completion: {})
}else{
  present(alert, animated: true, completion: {})
}

Note:It's swift3

Sardinian answered 30/4, 2017 at 2:14 Comment(1)
None of the other alerts in the application required a popoverMouse

© 2022 - 2024 — McMap. All rights reserved.