Robby
Robby

Reputation: 207

How to update .setTitle for a UIButton using didSet?

I'm working with a profile registration view controller, I want to update the title of my UIButton when the user picks the city from the UIPickerController. The title from the button is not updating after the user picks the city.

I try using DispatchQueue.main.async and is not working as well I'm trying to update didSet after dismissing the view from where I present the city picker. When I run my code the value is giving the correct title but is not updating and reloading the data from my view.

First View

 import UIKit
import Firebase

class PersonalInfoController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

//MARK: Variables
var finalCity: String? {
    didSet {
        guard let userCity = self.finalCity else { return }
        print(cityPicker.currentTitle)
        self.cityPicker.setTitle(userCity, for: .normal)
        print(cityPicker.currentTitle)
    }
}

let cityPicker: UIButton = {
    let button = UIButton(type: .system)
    button.setTitle("City", for: .normal)
    button.backgroundColor = UIColor.rgb(red: 248, green: 101, blue: 46)
    button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17)
    button.setTitleColor(UIColor.white, for: .normal)
    button.layer.cornerRadius = 20
    button.clipsToBounds = true
    button.addTarget(self, action: #selector(handlePickCity), for: .touchUpInside)
    return button
}()
//MARK: ViewDidLoad
override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.rgb(red: 235, green: 235, blue: 228)
    navigationController?.isNavigationBarHidden = true
    setupSubViews()
    stackView()
}
@objc func handlePickCity() {
    let selectVC = UINavigationController(rootViewController: SelectCity())
    selectVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
    present(selectVC, animated: true, completion: nil)
}

Second View(picker presenting)

import UIKit

class SelectCity: UIViewController {

//MARK: Variables
let cities = ["Chico", "Orland"]
let picker = CityPicker()
var selectedCity: String?

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.black.withAlphaComponent(0.7)

    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(handleDone))

    picker.delegate = self
    picker.dataSource = self
    view.addSubview(picker)
    picker.anchor(top: nil, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}

//MARK: Action Handler
@objc func handleDone(){
    let userInfoVC = PersonalInfoController()
    userInfoVC.finalCity = selectedCity
    self.dismiss(animated: true, completion: nil)
}
}

extension SelectCity: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return cities.count
}

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

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    selectedCity = cities[row]
}
}

My console is printing the currentTitle before and after. This is the console:

This one is the current after the user picks the city from the picker Optional("City")

This one is after the user picks the city Optional("Orland")

Upvotes: 1

Views: 1119

Answers (2)

Natarajan
Natarajan

Reputation: 3271

Your problem is in below method, In which you are creating new controller and assigning selectedCity string to the new instance. So that your existing PersonalInfoController won't be updated.

//MARK: Action Handler
@objc func handleDone(){
    let userInfoVC = PersonalInfoController() //New PersonalInfoController is creating and existing controller won't be updated.
    userInfoVC.finalCity = selectedCity
    self.dismiss(animated: true, completion: nil)
}

So you may have to follow some Delegate pattern to send data between ViewControllers.

Example:

protocol SelectCityDelegate {

    func didSelectCity(_ city:String)
}

class PersonalInfoController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, SelectCityDelegate {

    //////

    @objc func handlePickCity() {

        let selectCityController = SelectCity()
        selectCityController.delegate = self

        let selectVC = UINavigationController(rootViewController: selectCityController)

        selectVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        present(selectVC, animated: true, completion: nil)
    }

    func didSelectCity(_ city: String) {

        finalCity = city
    }

    //////
}

class SelectCity: UIViewController {

    /////

    weak var delegate:SelectCityDelegate?

    //MARK: Action Handler
    @objc func handleDone(){

        delegate?.didSelectCity(selectedCity)

        self.dismiss(animated: true, completion: nil)
    }

    /////
}

But I will recommend you to implement the City Picker view within your PersonalInfoController instead of creating new controller just for a picker.

Upvotes: 1

Viren Malhan
Viren Malhan

Reputation: 115

Problem is your cityPicker is creating new instance of button everytime.

You can do

var cityPicker: UIButton = UIButton()

create a method which will return UIButton.

func getButton() -> UIButton { 
  let button = UIButton(type: .system)
    button.setTitle("City", for: .normal)
    button.backgroundColor = UIColor.rgb(red: 248, green: 101, blue: 46)
    button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 17)
    button.setTitleColor(UIColor.white, for: .normal)
    button.layer.cornerRadius = 20
    button.clipsToBounds = true
    button.addTarget(self, action: #selector(handlePickCity), for: .touchUpInside)
    return button
}

cityPicker = getButton()

then you can set title

cityPicker.setTitle(userCity, for: .normal)

Upvotes: 1

Related Questions