Reputation: 207
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
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
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