Search code examples
iosswiftuipickerviewuialertcontroller

Swift 5: How can get the selected PickerView value inside a UIAlert Textfield?


I'm struggling to implement a UIPickerView inside the UIAlert as an input for the textfield. Here's what I've got (think of a simple TODO app);

import UIKit

class ViewController: UIViewController {
    
    let todoItemCategory = ["Work", "Home", "Friends", "Buy stuff"]
    let pickerView = UIPickerView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        pickerView.dataSource = self
        pickerView.delegate = self
    }

    @IBAction func addItemButtonPressed(_ sender: Any) {
        let alert = UIAlertController(title: "Add a new todo item", message: "Provide the title and the category of the new item.", preferredStyle: .alert)
        
        alert.addTextField { field in
            field.placeholder = "Type the item title"
            field.returnKeyType = .next
        }
        alert.addTextField { field in
            field.placeholder = "Select category"
            
            field.inputView = self.pickerView
        }
        
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        alert.addAction(UIAlertAction(title: "Save", style: .default, handler: { _ in
            guard let fields = alert.textFields, fields.count == 2 else {
                return
            }
            let itemTitleField = fields[0]
            let categoryField = fields[1]
            
            guard let itemTitle = itemTitleField.text, !itemTitle.isEmpty, let category = categoryField.text, !category.isEmpty else {
                print("Invalid entries")
                return
            }
            
            print(itemTitle)
            print(category)
            
        }))
        
        present(alert, animated: true)
    }
}

//MARK: - Pickerview datasource & delegate methods

extension ViewController: UIPickerViewDataSource {
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return todoItemCategory.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return todoItemCategory[row]
    }
    
    
}

extension ViewController: UIPickerViewDelegate {
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        // Update the textfield inside the UIAlert
    }
}

What I've done is;

  • A UIAlert view pops up when the user clicks on the button (addItemButtonPressed).
  • In the "Select category" textfield, I linked to the PickerView as an input view. The Pickerview with possible categories will then appear as selectable options.

The picker view appears nicely, but whenever the user selects one of the values, nothing happens. I want the textfield to show the selected category, and I know I need to do something inside

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        // Update the textfield inside the UIAlert
    }

I was going to assign the selected value to a global variable, let's say currentSelectedCategory, but I do not know how to make the UIAlert textfield to read it up again whenever the value gets changed.

Appreciate your help in advance to this poor swift newbie!


Solution

  • Set a UIAlertController object reference outside the button action and access it.

    class ViewController: UIViewController {
        
        // Other code
        
        var alert: UIAlertController = UIAlertController()
        
        // Other code
        @IBAction func addItemButtonPressed(_ sender: Any) {
            alert = UIAlertController(title: "Add a new todo item", message: "Provide the title and the category of the new item.", preferredStyle: .alert)
            
            // Other code
        }
    }
    
    extension ViewController: UIPickerViewDelegate {
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            // Update the textfield inside the UIAlert
            alert.textFields?.last?.text = todoItemCategory[row]
        }
    }