Issue updating UIPickerView in Swift with user inputted data into an array - ios

I'm writing a simple fitness app that allows the user to add user profiles which are displayed in a UIPickerView, and when selected, is entered into the profileField label on the main ViewController. The pickerView uses an array of Profile objects as its data source and displays the name of the profile in the picker. I have it set up to where the user clicks a button on the main ViewController and is segued to the AddProfileViewController where they input the necessary requirements to create a profile. When they hit submit the information successfully gets appended to the profileNames array but the pickerView does not show any changes when the user clicks back on it. I have tried using pickerView.reloadAllComponents() and pickerView.reloadComponent(1) to no success.
I am on Xcode Version 12.4 (12D4e)
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource
{
#IBOutlet weak var profileField: UITextField!
#IBAction func didTapEnter(_ sender: Any)
{
}
#IBAction func didTapNewProfile(_ sender: Any)
{
}
//these are pre-populated values in this array
var profileNames: [Profile] =
[
Profile("Brandon", 2, 120, 20, "Male"),
Profile("G", 2, 100, 20, "Male"),
Profile("K", 1.6, 111, 19, "Male"),
Profile("F", 2.1, 95, 20, "Male"),
Profile("J", 1.89, 97.5, 21, "Male")
]
var pickerView = UIPickerView()
override func viewDidLoad()
{
super.viewDidLoad()
pickerView = UIPickerView()
pickerView.delegate = self
pickerView.dataSource = self
profileField.inputView = pickerView
profileField.textAlignment = .center
profileField.placeholder = "Enter Profile"
}
func numberOfComponents(in pickerView: UIPickerView) -> Int
{
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
return profileNames.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
return profileNames[row].name
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
profileField.text = profileNames[row].name
profileField.resignFirstResponder()
}
func profileSubmit(_ data: Profile)
{
profileNames.append(data)
pickerView.reloadComponent(1) //This does not seem to do anything for me
}
}
class AddProfileViewController: UIViewController, UINavigationControllerDelegate
{
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var weightTextField: UITextField!
#IBOutlet weak var heightTextField: UITextField!
#IBOutlet weak var ageTextField: UITextField!
#IBOutlet weak var sexTextField: UITextField!
let main: ViewController? = nil
#IBAction func submit(_ sender: Any)
{
let name = String(nameTextField.text!)
let height = Double(heightTextField.text!)!
let weight = Double(weightTextField.text!)!
let age = Double(ageTextField.text!)!
let sex = String(sexTextField.text!)
let new = Profile.init(name, height, weight, age, sex)
main?.profileSubmit(new)
new.display()
dismiss(animated: true, completion: nil)
}
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

I guess that on coming back from newProfile viewDidLoad is called -> you reset the picker in viewDidLoad by setting it to a new instance. Try to remove the new initialization in viewDidLoad :
super.viewDidLoad()
pickerView = UIPickerView()
The picker is already initialized here:
var pickerView = UIPickerView()
Also, I think the picker components start with 0 - so if there is only 1 component it should be:
pickerView.reloadComponent(0)

Related

Error: Cannot assign to immutable expression of type ‘[String].Type’

I’m very new in Swift and trying to use int values 0-10 in my UIPickerView but there’s some errors that I don’t really understand.
Here’s my code - I’m putting the UIPickerView inside a TextField I just thought it looked neater that way.
class AddViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var repeatTextField: UITextField!
#IBOutlet weak var startPicker: UIDatePicker!
#IBOutlet weak var endPicker: UIDatePicker!
#IBOutlet weak var doneButton: UIBarButtonItem!
var pickerView = UIPickerView()
var numbers = [String] = []
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
repeatTextField.inputView = pickerView
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
pickerView.delegate = self
pickerView.dataSource = self
for i in 1..<10 {
numbers.append(String(i))
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 10
}
internal func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return String(row + 1)
}
}
This is where the error shows up:
var numbers = [String] = []
I can only rlly see tutorials of using UIPickerView with String but not Int.
This is what I’m trying to attain:
enter image description here
Could you please help me how to resolve this? Thanks in advance! :))
You can: var numbers: [String] = [] or var numbers = [String]()

Problem using two UIPickerViews - first works, second doesnt

Im trying to use two pickerviews on two different textboxes (i align them underneath the textboxes and hide them until called). I hide the pickerviews until i'm ready to use and tie both textboxes to their corresponding textbox. The first pickerview works fine, but when i click on the second, my list doesnt appear and it appears still hidden. I've read thru the code multiple times and cannot find the issue and have watched multiple videos and checked apples documentation to no avail. Code posted below for review and help. Thanks in advance!
class fifthViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
#IBOutlet weak var heightInput: UITextField!
#IBOutlet weak var weightInput: UITextField!
#IBOutlet weak var bmiOutput: UITextField!
#IBOutlet weak var weightPicker: UIPickerView!
#IBOutlet weak var heightPicker: UIPickerView!
var height = ["48", "49", "50"]
var weight = ["90", "91", "92"]
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
var countrows : Int = height.count
if pickerView == weightPicker {
countrows = self.weight.count
}
return countrows
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView == heightPicker {
let titleRow = height[row]
return titleRow
}
else if pickerView == weightPicker {
let titleRow = weight[row]
return titleRow
}
return ""
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == heightPicker {
self.heightInput.text = self.height[row]
self.heightPicker.isHidden = true
}
else if pickerView == weightPicker {
self.weightInput.text = self.weight[row]
self.weightPicker.isHidden = true
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if (textField == self.heightInput) {
self.heightPicker.isHidden = false
}
else if (textField == self.weightInput) {
self.weightInput.isHidden = false
}
}```
In textFieldDidBeginEditing(), you need to set self.weightPicker.isHidden to false instead of self.weightInput.isHidden.
func textFieldDidBeginEditing(_ textField: UITextField) {
if (textField == self.heightInput) {
self.heightPicker.isHidden = false
}
else if (textField == self.weightInput) {
self.weightPicker.isHidden = false
}
}
Modify your code to use inputViews
I agree with #PaulW11's comment:
"You would be almost certainly better off if you made the picker views
the inputView of each text field."
Here are the changes you need for a basic setup. Get rid of the pickers in the Storyboard and disconnect the #IBOutlet connections.
Then add these modifications:
// These are no longer outlets since they're created in code
var weightPicker: UIPickerView!
var heightPicker: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
// set up the picker views
self.weightPicker = UIPickerView()
self.weightPicker.delegate = self
self.weightPicker.dataSource = self
self.heightPicker = UIPickerView()
self.heightPicker.delegate = self
self.heightPicker.dataSource = self
self.heightInput.inputView = self.heightPicker
self.weightInput.inputView = self.weightPicker
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == heightPicker {
self.heightInput.text = self.height[row]
// make picker go away after value has been selected
self.heightInput.resignFirstResponder()
}
else if pickerView == weightPicker {
self.weightInput.text = self.weight[row]
// make picker go away after value has been selected
self.weightInput.resignFirstResponder()
}
}

How to remove and add items in uipickerview in swift 4.?

I have three text fields for which I am showing the same pickerview as drop down for choosing the values. So the condition is that I have 5 values in an array with values red, blue, green, yellow, black.
So the condition is
These three text fields cannot have same value. That is if for first textfield 1 if I choose red as value from picker the value " red " should be removed or disabled from picker view when I select textfield 2 or text field 3 .
And if I change the value of textfield 1 from red to black from picker view the value red which is disabled or removed should get added back to the pickerview when I click on textfield 2 or textfield 3.
The code which I am trying is:
import UIKit
class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
#IBOutlet weak var textFiled1: UITextField!
#IBOutlet weak var textFiled2: UITextField!
#IBOutlet weak var textFiled3: UITextField!
#IBOutlet weak var pickerView: UIPickerView!
var Array = ["Blue", "Green", "Red", "White", "Grey"]
var indexOfPicker = Int()
override func viewDidLoad() {
super.viewDidLoad()
pickerView.dataSource = self
pickerView.delegate = self
}
#IBAction func minusButton(_ sender: UIButton) {
if Array.count != 0 {
Array.remove(at: indexOfPicker)
pickerView.reloadAllComponents()
}
}
#IBAction func plusButton(_ sender: UIButton) {
if textFiled.text != "" {
Array.append(textFiled.text!)
pickerView.reloadAllComponents()
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return Array.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return Array[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
indexOfPicker = row
}
}
class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UITextFieldDelegate {
#IBOutlet weak var textFiled1: UITextField!
#IBOutlet weak var textFiled2: UITextField!
#IBOutlet weak var textFiled3: UITextField!
#IBOutlet weak var pickerView: UIPickerView!
var selectedTextField:UITextField?
var colorsArray = ["Blue", "Green", "Red", "White", "Grey"]
override func viewDidLoad() {
super.viewDidLoad()
textFiled1.delegate = self
textFiled2.delegate = self
textFiled3.delegate = self
pickerView.dataSource = self
pickerView.delegate = self
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
let tempArr = colorsArray.filter { ![textFiled1.text!,textFiled2.text!,textFiled3.text!].contains($0) }
return tempArr.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
let tempArr = colorsArray.filter { ![textFiled1.text!,textFiled2.text!,textFiled3.text!].contains($0) }
return tempArr[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let tempArr = colorsArray.filter { ![textFiled1.text!,textFiled2.text!,textFiled3.text!].contains($0) }
self.selectedTextField?.text = tempArr[row]
pickerView.reloadAllComponents()
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.selectedTextField = textField
pickerView.reloadAllComponents()
}
}

UIPickerView delegate not called in a subview

I have a simple iOS app that uses UISegmentedControl to switch between two tabs.
In ViewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var segment: UISegmentedControl!
#IBOutlet weak var viewContainer: UIView!
var searchView: UIView!
var favView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
searchView = SearchViewController().view
favView = FavoriteViewController().view
viewContainer.addSubview(favView)
viewContainer.addSubview(searchView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func segmentChange(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex{
case 0:
viewContainer.bringSubview(toFront: searchView)
break
case 1:
viewContainer.bringSubview(toFront: favView)
break
default:
break
}
}
}
And in the first tab, I have a UIPickerView as input of a Textfield.
import UIKit
class SearchViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var keywordField: UITextField!
#IBOutlet weak var categoryField: UITextField!
#IBOutlet weak var distanceField: UITextField!
#IBOutlet weak var locationField: UITextField!
var cgpicker = UIPickerView()
let categories = ["Default", "Airport", "Amusement Park", "Aquarium", "Art Gallery", "Bakery", "Bar"]
override func viewDidLoad() {
super.viewDidLoad()
cgpicker.delegate = self
cgpicker.dataSource = self
categoryField.inputView = cgpicker
categoryField.text = categories[0]
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print("picker working")
return categories.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return categories[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
categoryField.text = categories[row]
categoryField.resignFirstResponder()
}
}
However, when I click the Textfield, the PickerView doesn't display data. In fact the delegate and datasource is not called since the "print" is never called. However the same code is working fine in a simple UIView app. I cannot find any solution related to this problem.
UIPickerView not showing data
The problem is with the viewDidLoad of your ViewController class.
You are not creating the container view controller properly. The primary issue preventing the picker from working is that your SearchViewController has no strong reference to it when viewDidLoad finishes so the picker in SearchViewController becomes nil.
Update the ViewController viewDidLoad to something like this:
override func viewDidLoad() {
super.viewDidLoad()
let searchVC = SearchViewController()
searchView = searchVC.view
addChildViewController(searchVC)
// Should set searchView frame or constraints
viewContainer.addSubview(searchView)
searchVC.didMove(toParentViewController: self)
let favVC = FavoriteViewController()
favView = favVC.view
addChildViewController(favVC)
// Should set favView frame or constraints
viewContainer.addSubview(favView)
favVC.didMove(toParentViewController: self)
}
This because you not load picker
you should have reference to SearchViewController not reference to its View
ViewController:
class ViewController: UIViewController {
#IBOutlet weak var segment: UISegmentedControl!
#IBOutlet weak var viewContainer: UIView!
var searchController: SearchViewController!
var favController: FavoriteViewController!
override func viewDidLoad() {
super.viewDidLoad()
searchController = SearchViewController()
favController = FavoriteViewController()
viewContainer.addSubview(searchController.view)
viewContainer.addSubview(favController.view)
searchController.loadPickerView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func segmentChange(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex{
case 0:
viewContainer.bringSubview(toFront: searchController.view)
searchController.loadPickerView()
break
case 1:
viewContainer.bringSubview(toFront: favController.view)
break
default:
break
}
}
}
Add loadPickerView func to SearchViewController
func loadPickerView() {
cgpicker.delegate = self
cgpicker.dataSource = self
self.textFieldUserName.inputView = cgpicker
textFieldUserName.text = categories[0]
}

Pass data back in navigation controller Swift 3

I am rather new to Xcode and Swift and I am trying to pass data back from a previous page. So far what I have works but it leverages the segue I created to show the previous page. This would not be a problem except it is in a navigation view controller. So when you click the save button it passes the data to my choices view controller but if you click the back button on the page it goes back to the editing page. I want it to instead travel back in the navigation pane so that way when you click the back page it instead takes it to the page that says view my chart. So I don't think using a segue to do this is the right option because I am typically passing the data forward. I want to pass the data back to the previous navigation view controller. You will see my cancel button does this.
Story Board
Edit ViewController
class EditUserViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
var officeSelected = ""
var utilSelected = ""
#IBOutlet weak var officePicker: UIPickerView!
#IBOutlet weak var slider: UISlider!
#IBAction func UtilSlider(_ sender: UISlider) {
slider.value = roundf(slider.value)
utilSelected = String(Int(sender.value))
}
let offices = ["NYC", "LA", "Boston"]
func numberOfComponents(in pickerView: UIPickerView) -> Int
{
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
return offices.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
return offices[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
officeSelected = offices[row]
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func CancelEdit(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let choicesView = segue.destination as! ChoicesViewController
choicesView.officeText = officeSelected
choicesView.utilText = utilSelected
}
}
choices ViewController
class ChoicesViewController: UIViewController{
#IBOutlet weak var officeLabel: UILabel!
#IBOutlet weak var AvalLabel: UILabel!
var utilText = String()
var officeText = String()
override func viewDidLoad() {
super.viewDidLoad()
officeLabel.text = officeText
AvalLabel.text = utilText
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Resources