I created a reusable control to be used in a project I'm working on. It's just a UITextField
which shows a UIPickerView
as its inputView
.
class InputPickerView: UIView {
@IBOutlet private var view: UIView!
@IBOutlet weak private var titleLabel: UILabel!
@IBOutlet weak private var textField: UITextField!
private(set) var pickerView = UIPickerView()
var options: [String] = []
var option: String {
get {
return textField.text ?? ""
}
set {
textField.text = newValue
}
}
var title: String = "" {
didSet {
titleLabel.text = title
}
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("InputPickerView", owner: self, options: nil)
addSubview(view)
view.frame = bounds
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
pickerView.dataSource = self
pickerView.delegate = self
textField.inputView = pickerView
}
}
extension InputPickerView: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return false
}
}
extension InputPickerView: UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return options.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return options[row]
}
}
extension InputPickerView: UIPickerViewDelegate {
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
textField.text = options[row]
}
}
Currently it only accepts an array of strings and returns a string. I'm trying to make it even more reusable by make it accept/return any types such as structs and enums with the help of generics. I was hoping to make the structs/enums conform to CustomStringConvertible
and use the description property value as the display value for the picker view options.
But I'm having trouble figuring out how to do that. All the articles, questions, tutorials I came across have protocols involved in them. So I'm a little confused.
How can I make the options
and option
variables accept/return any type with generics?
By which I mean, say I create an object called State
.
struct State {
let id: Int
let title: String
}
extension State: CustomStringConvertible {
var description: String {
return title
}
}
Instead of passing in strings to the view, I'm trying to make it accept instances of State
objects in the options
property and have the view use the description
value as the display value. And when the user selects one, it returns the selected State
object via the option
property.