@IBAction crashes when recursively called

169 views Asked by At

I am having this crash happening when I recursively call @IBAction

0   Goga  0x00000001000b90b8 function signature specialization <Arg[0] = Owned To Guaranteed, Arg[1] = Owned To Guaranteed> of Goga.NewViewController.emailButtonPressed (Goga.NewViewController)(ObjectiveC.UIButton) -> () (NewViewController.swift:0)
1   Goga  0x00000001000c0488 Goga.NewViewController.(emailButtonPressed (Goga.NewViewController) -> (ObjectiveC.UIButton) -> ()).(closure #2) (NewViewController.swift:872)
2   Goga  0x00000001000bd250 partial apply forwarder for reabstraction thunk helper from @callee_owned (@in ObjectiveC.UIAlertAction!) -> (@out ()) to @callee_owned (@owned ObjectiveC.UIAlertAction!) -> (@unowned ()) (NewViewController.swift:0)

This is the code and the line that's happening in it

allowedToSend = false
@IBAction func emailButtonPressed(sender: UIButton) {

  if !allowedToSend {

    let controller = UIAlertController(title: title,
                    message: "Are you sure you want to send the Email?",
                    preferredStyle: .Alert) 

     controller.addAction(UIAlertAction(title: "Yes please, send.", style: .Default, handler: {
                    action in

                    self.allowedToSend = true; 
                    self.emailButtonPressed(sender) <=== WHERE THE CRASH HAPPENED
            }))  

     controller.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: nil))
     presentViewController(controller, animated: true, completion: nil)
     return // exit the function

  }

  // Reset the value
  allowedToSend = false

  // Sending code

  let text = textArea.text
  let to = toLabel.text

    ....    

}   

You might ask, why I don't put the "Sending code" in the handler, because I am doing this only for a specific case where the user is about to commit a mass sending to all the contacts in his address book. Therefore, I am reminding her, that she's going to do that before sending.

I am not sure what is the problem with such implementation and why Swift complains about this, given that I tested this in debug mode and it looks fine. Why is this happening?

EDIT

It would nice if I can get some insight into the meaning of the crash.

3

There are 3 answers

1
picciano On

I would suggest breaking up the function for readability and maintainability. This will also solve any problems with recursion and eliminate the need for an allowedToSend property. In any case, it will be easier to debug since the execution path is simplified.

@IBAction func emailButtonPressed(sender: UIButton) {
    self.confirm();
}

func confirm() {
    let controller = UIAlertController(title: title,
                message: "Are you sure you want to send the Email?",
                preferredStyle: .Alert) 

    controller.addAction(UIAlertAction(title: "Yes please, send.", style: .Default, handler: {
                action in 
                self.send()
    }))  

    controller.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: nil))
    presentViewController(controller, animated: true, completion: nil)
}

func send() {
    let text = textArea.text
    let to = toLabel.text
    ....
}
6
arturdev On

I think You have infinite recursion. Set a breakpoint on lines self.emailButtonPressed(sender) and allowedToSend = false and run the app and you will see that the second one never been called.

0
Mickey Mouse On

I found the issue. It has nothing to do with recursion or even breaking down the code into chunks. The issue was: the program crashed as it found nil while unwrapping an optional value. The odd thing is, that error message is no where to be found in the crash log file. So, to anyone who'll see this (and to my future self), always check your optionals.

Example:

let cell = tableView.cellForRowAtIndexPath(indexPath)
cell.textLabel.text = "Hello" // CRASH if the cell is not visible in the view

to fix the above, just wrap into if let

if let cell = tableView.cellForRowAtIndexPath(indexPath) {
   cell.textLabel.text = "Hello" // Never get executed if cell is nil
}