Is there way to get the text field value in UIAlertAction?

842 Views Asked by At

I'm trying to refactor the UIAlert in Swift and I want to make sure if there is a way to implement codes to achieve what I want to do now.

In my app, I need to show several UIAlertControllers, and to make files small, I'm making a custom function to display AlertController and takes methods to triger depending on user action (I mean... when cancel pressed, dismiss popup e.t.c.).

The one I'm working on is there is one TextField, and what I want to implement is when a user tap a "OK" action button, get the value of the TextField's value.

In my UIVC+Alert.swift file, I created an extension and add function, "showAlertWithTextField" like below.

import UIKit

extension UIViewController {
    
    func showAlertWithTextField(title: String?, message: String?, actions: [UIAlertAction], style: UIAlertController.Style, completion: (() -> Void)?) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: style)
        alert.addTextField { (textField) in
            print("textField \(textField.text)")
        }
        actions.forEach { alert.addAction($0)}
        present(alert, animated: true, completion: completion)
    }
}

Then, this. function is called from other swift file, ViewController.swift.

func showAlert() {
    let editAction = UIAlertAction(title: "Edit", style: .destructive) { _ in

        // want to get the value of textFields in here...
        if let title = <How to access the textfield value ??> {
                print("title: \(title)")
        }
     }
     self.showAlertWithTextField(title: "test", message: nil, actions: [editAction], style: .alert, completion: nil)

}

usually, I don't make an extension file, and I write everything in the same file, so I can access the value with using something like, alert.textFields![0].text. But in this case, when I use alert.addTextField in showAlertWithTextField function, the user hasn't type anything and get empty string (which make sense). But is there way to access alert's textfield when the user hit "Edit" button (triggered the editAction button)?

2

There are 2 best solutions below

2
vadian On BEST ANSWER

A swifty way is to add a temporary variable for the text field and a handler to assign the text field of the alert to the variable

func showAlert() {
    weak var textField : UITextField?

    let editAction = UIAlertAction(title: "Edit", style: .destructive) { _ in
        print("Edit Pressed", textField?.text ?? "n/a")
    }
    let handler : (UITextField) -> Void = { textField = $0 }
    self.showAlertWithTextField(title: "test", message: nil, actions: [editAction], style: .alert, handler: handler, completion: nil)

}

In the extension call the handler right after the text field has beed added

extension UIViewController {
    
    func showAlertWithTextField(title: String?, message: String?,
                                actions: [UIAlertAction],
                                style: UIAlertController.Style,
                                handler: ((UITextField) -> Void)? = nil,
                                completion: (() -> Void)?) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: style)
        alert.addTextField { handler?($0) }
        actions.forEach { alert.addAction($0)}
        present(alert, animated: true, completion: nil)
    }
}
0
Abdul Waheed On

You can get top View controller which will be safely unwrapped to an Alert Controller

let editAction = UIAlertAction(title: "Edit", style: .destructive) { _ in

          let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
 
          if var topController = keyWindow?.rootViewController {
            while let presentedViewController = topController.presentedViewController as? UIAlertController {
        topController = presentedViewController
              }

// topController should now be your topmost view controller

 if let title = topController.textFields?[0].text{
                print("title: \(title)")
        }
   }
       
}