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

Posted

技术标签:

【中文标题】如何使用 didSet 更新 UIButton 的 .setTitle?【英文标题】:How to update .setTitle for a UIButton using didSet? 【发布时间】:2018-12-26 07:08:47 【问题描述】:

我正在使用个人资料注册视图控制器,当用户从 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。 这是控制台:

这是用户从picker中选择城市后的当前 可选(“城市”)

这个是用户选择城市后的 Optional("Orland")

【问题讨论】:

【参考方案1】:

您的问题出在下面的方法中,您正在创建新控制器并将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 中实现 City Picker 视图,而不是仅为选择器创建新控制器。

【讨论】:

谢谢。我想在同一个视图中输入我的代码,但我不知道我在想什么。投票回答和推荐【参考方案2】:

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

你可以的

var cityPicker: UIButton = UIButton()

创建一个返回 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)

【讨论】:

以上是关于如何使用 didSet 更新 UIButton 的 .setTitle?的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中 @Binding 变量的 didSet

如何使用 `Codable` 协议调用`didSet` 方法

将CABasicAnimation添加到子类UIButton - 如果已启用

已发布值上的 SwiftUI toggle() 函数停止使用 Swift 5.2 触发 didSet

SwiftUI - 更改 @Published 结构时是不是可以触发 didSet?

在 SwiftUI 中,我如何知道 Picker 选择何时更改?为啥 didSet 不起作用?