Search code examples
iosswiftuiviewcontrolleruipickerview

UIPickerView delegate not called in a subview


I have a simple iOS app that uses UISegmentedControl to switch between two tabs.

In ViewController.swift:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var segment: UISegmentedControl!
    @IBOutlet weak var viewContainer: UIView!
    var searchView: UIView!
    var favView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    searchView = SearchViewController().view
    favView = FavoriteViewController().view
    viewContainer.addSubview(favView)
    viewContainer.addSubview(searchView)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

@IBAction func segmentChange(_ sender: UISegmentedControl) {
    switch sender.selectedSegmentIndex{
    case 0:
        viewContainer.bringSubview(toFront: searchView)
        break
    case 1:
        viewContainer.bringSubview(toFront: favView)
        break
    default:
        break
    }
}
}

And in the first tab, I have a UIPickerView as input of a Textfield.

import UIKit

class SearchViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var keywordField: UITextField!
    @IBOutlet weak var categoryField: UITextField!
    @IBOutlet weak var distanceField: UITextField!
    @IBOutlet weak var locationField: UITextField!

    var cgpicker = UIPickerView()
    let categories = ["Default", "Airport", "Amusement Park", "Aquarium", "Art Gallery", "Bakery", "Bar"]

override func viewDidLoad() {
    super.viewDidLoad()
    cgpicker.delegate = self
    cgpicker.dataSource = self
    categoryField.inputView = cgpicker
    categoryField.text = categories[0]
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    print("picker working")
    return categories.count
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return categories[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    categoryField.text = categories[row]
    categoryField.resignFirstResponder()
}

}

However, when I click the Textfield, the PickerView doesn't display data. In fact the delegate and datasource is not called since the "print" is never called. However the same code is working fine in a simple UIView app. I cannot find any solution related to this problem.

UIPickerView not showing data


Solution

  • The problem is with the viewDidLoad of your ViewController class.

    You are not creating the container view controller properly. The primary issue preventing the picker from working is that your SearchViewController has no strong reference to it when viewDidLoad finishes so the picker in SearchViewController becomes nil.

    Update the ViewController viewDidLoad to something like this:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let searchVC = SearchViewController()
        searchView = searchVC.view
        addChildViewController(searchVC)
        // Should set searchView frame or constraints
        viewContainer.addSubview(searchView)
        searchVC.didMove(toParentViewController: self)
    
        let favVC = FavoriteViewController()
        favView = favVC.view
        addChildViewController(favVC)
        // Should set favView frame or constraints
        viewContainer.addSubview(favView)
        favVC.didMove(toParentViewController: self)
    }