如何使用 didSet 更新 UIButton 的 .setTitle?

How to update .setTitle for a UIButton using didSet?

我正在使用配置文件注册视图控制器,我想在用户从 UIPickerController 选择城市时更新我的​​ UIButton 的标题。用户选择城市后,按钮的标题不会更新。

我尝试使用 DispatchQueue.main.async 但效果不佳 我在关闭显示城市选择器的视图后尝试更新 didSet。当我 运行 我的代码时,值给出了正确的标题,但没有从我的视图中更新和重新加载数据。

第一次观看

 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)
}

第二个视图(选择器呈现)

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]
}
}

我的控制台在前后打印 currentTitle。 这是控制台:

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")

问题是您的 cityPicker 每次都在创建新的按钮实例。

你可以做到

var cityPicker: UIButton = UIButton()

创建一个方法,它将 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()

然后你可以设置标题

cityPicker.setTitle(userCity, for: .normal)

您的问题出在以下方法中,您在其中创建新控制器并将 selectedCity 字符串分配给新实例。这样您现有的 PersonalInfoController 就不会更新。

//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)
}

因此您可能必须遵循一些 Delegate 模式才能在 ViewController 之间发送数据。

示例:

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)
    }

    /////
}

但我建议您在 PersonalInfoController 中实现城市选择器视图,而不是仅为选择器创建新控制器。