Kee Reel Kee Reel - 1 month ago 9
Swift Question

How to get access to button placed on UIAlertController from handler of UITextField placed on UIAlertController?

i’m using UIAlertController for asking user enter a string, and this string should not be empty. For this purpose i'm adding handler for every editing event on UITextField located on UIAlertController. This handler checks, if the textField is empty, it makes «OK» button (located on UIAlertController) disabled, and, if the textField is not empty, it makes «OK» button enabler. «OK» button also located on UIAlertController.
I have a problem with access to the «OK» button from this
handler function:


  1. There is no opportunity to pass the button as a parameter directly to the handler function because i’m calling it using #selector.

  2. I’ve also tried to access UIAlertController through the UITextField.superview from handler function, but it didn’t work: it returned UIView, which can’t be downcasted to UIAlertController. And it’s not clear why it is so: UITextField is subview of UIAlertController and consequently UITextField.superview must return UIAlertController.

  3. I’ve also tried the easiest way: declare UIAlertController as property in my ViewController class: this allows me to access the button from handler function without passing it directly to function. But in this case i’ve collided with another problem: at the runtime Xcode shows this warning in debug area: Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior ()




And my question is how to get access to «OK» button from my handler function?

class TVC_ProgramsList: UITableViewController {

var enterNameAC = UIAlertController()

@IBAction func addpush(sender: UIBarButtonItem) {
addProgram()
}

func addProgram() {

enterNameAC = UIAlertController(title: "Adding program", message: "Enter program name", preferredStyle: UIAlertControllerStyle.Alert)
enterNameAC.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil))
enterNameAC.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
enterNameAC.addTextFieldWithConfigurationHandler { (textField) -> Void in
textField.placeholder = "Program name"

textField.addTarget(self, action: #selector(TVC_ProgramsList.enterProgramNameAC_editingTextField), forControlEvents: UIControlEvents.AllEditingEvents)

}

self.presentViewController(enterNameAC, animated: true, completion: nil)

}


func enterProgramNameAC_editingTextField() {
let programNameString = enterNameAC.textFields![0].text!

if programNameString.characters.count > 0 {
enterNameAC.actions[1].enabled = true
} else {
enterNameAC.actions[1].enabled = false
}
}

}

Answer

Why don't you make an attribute of the UIAlertAction? I've changed your code:

class TVC_ProgramsList: UITableViewController {

  var enterNameAC = UIAlertController()
  let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)

  @IBAction func addpush(sender: UIBarButtonItem) {
     addProgram()
  }

  func addProgram() {
    enterNameAC = UIAlertController(title: "Adding program", message: "Enter program name", preferredStyle: UIAlertControllerStyle.Alert)
    enterNameAC.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil))
    enterNameAC.addAction(self.okAction)
    enterNameAC.addTextFieldWithConfigurationHandler { (textField) -> Void in
        textField.placeholder = "Program name"
        textField.addTarget(self, action: #selector(TVC_ProgramsList.enterProgramNameAC_editingTextField), forControlEvents: UIControlEvents.AllEditingEvents)

    }

    self.presentViewController(enterNameAC, animated: true, completion: nil)

  }

  func enterProgramNameAC_editingTextField() {
    let programNameString = enterNameAC.textFields![0].text!
    // use okAction here 
    self.okAction.enabled = programNameString.characters.count > 0
  }
}

Passing it with addTarget won't be possible. But it's a valid approach to make a class attribute out of it and therefore making it accessible in other parts of your ViewController.

Comments