0

Still pretty new to swift, I was having some trouble passing updated data into the pickerview. I'm receiving the "index out of range" error. I have a suspicion that the uipickerview is seeing the empty array, even though the arrays are getting updated. Any help is much appreciated.

import UIKit

class ViewController: UIViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var nameDisplay: UILabel!
    @IBOutlet weak var ageDisplay: UILabel!
    @IBOutlet weak var emailDisplay: UILabel!
    @IBOutlet weak var pickerView: UIPickerView!



    @IBOutlet weak var txtfirstName: UITextField!
    @IBOutlet weak var txtAge: UITextField!
    @IBOutlet weak var txtEmail: UITextField!
    @IBOutlet weak var lblValidationMessage: UILabel!

    var ages = [Int]()
    var emailAddresses = [String]()
    var firstNames = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()
        //     lblValidationMessage.isHidden = true
        // Do any additional setup after loading the view.

        //links txtAge to the UITextField class, which gives access to func textfield
        txtAge?.delegate = self
        pickerView?.dataSource = self
        pickerView?.delegate = self
    }

    // restricts the values possible to input in txtAge.text

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        let allowedCharacters = "1234567890"
        let allowedCharcterSet = CharacterSet(charactersIn: allowedCharacters)
        let typedCharcterSet = CharacterSet(charactersIn: string)
        return allowedCharcterSet.isSuperset(of: typedCharcterSet)
    }

    @IBAction func addUserButton(_ sender: UIButton) {

        //validation of data in the text boxes

        lblValidationMessage.isHidden = true
        if let firstName = txtfirstName.text, firstName == "" {
            lblValidationMessage.isHidden = false
            lblValidationMessage.text = "Enter Your Name"
            return
        }

        if let age = txtAge.text, age == "" {
            lblValidationMessage.isHidden = false
            lblValidationMessage.text = "Please enter a numerical age"
            return
        }

        if let email = txtEmail.text, email.isEmpty {
            lblValidationMessage.isHidden = false
            lblValidationMessage.text = "Please enter an email address"
            return
        }


        //MARK: Adds entries to the 3 arrays

        firstNames.append(txtfirstName.text!)

        //Converts string to int, the age array requires INT
        let age:Int! = Int(txtAge.text!)
        ages.append(age)

        emailAddresses.append(txtEmail.text!)



        txtfirstName.text = ""
        txtAge.text = ""
        txtEmail.text = ""

        //Brings focus back to First Name text field
        txtfirstName.becomeFirstResponder()
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return firstNames.count
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        nameDisplay.text = firstNames[row]
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return firstNames[row]
    }

}

siburb
  • 4,880
  • 1
  • 25
  • 34
  • When is it crashing? When the VC first appears, or when you press the "addUser" button? Are you calling `reloadAllComponents()` anywhere (or `reloadComponent()`? – siburb Nov 21 '19 at 02:41
  • The fields are populated in the first vc, addUser updates the array, i segue to a vc that contains the pickerview, it shows the an empty picker and then it crashes with "index out of range". When i hard code the contents of the firstnames array, the pickerview is populated correctly. – MichaelG Nov 21 '19 at 02:52

2 Answers2

0

Try calling reloadAllComponents() after you change your data

vijeesh
  • 1,317
  • 1
  • 17
  • 32
  • Thanks for the reply, I've tried adding pickerView.reloadAllComponents () now I'm getting "Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value." Am I updating my Array correctly? it seems the pickviewView isn't seeing the appended items, or the data isn't refreshing. I've also tried reloadAllComponenets in various places, but still no luck. – MichaelG Nov 21 '19 at 13:09
  • I changed the array declarations to static var, and now it works. – MichaelG Nov 21 '19 at 15:47
0

It looks to be working with static var declarations for updating the arrays, I'm not sure it's programmatically correct. I do think structs would be a better approach. Anyway, thanks for the help on to the next error!

//  ViewController.swift

import UIKit

class ViewController: UIViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource {

@IBOutlet weak var nameDisplay: UILabel!
@IBOutlet weak var ageDisplay: UILabel!
@IBOutlet weak var emailDisplay: UILabel!
@IBOutlet weak var pickerView: UIPickerView!

@IBOutlet weak var txtfirstName: UITextField!
@IBOutlet weak var txtAge: UITextField!
@IBOutlet weak var txtEmail: UITextField!
@IBOutlet weak var lblValidationMessage: UILabel!

static var ages = [Int]()
static var emailAddresses = [String]()
static var firstNames = [String]()

override func viewDidLoad() {
    super.viewDidLoad()
    //     lblValidationMessage.isHidden = true
    // Do any additional setup after loading the view.

    txtAge?.delegate = self
    pickerView?.dataSource = self
    pickerView?.delegate = self
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let allowedCharacters = "1234567890"
    let allowedCharcterSet = CharacterSet(charactersIn: allowedCharacters)
    let typedCharcterSet = CharacterSet(charactersIn: string)
    return allowedCharcterSet.isSuperset(of: typedCharcterSet)
}

@IBAction func addUserButton(_ sender: UIButton) {

    lblValidationMessage.isHidden = true
    if let firstName = txtfirstName.text, firstName == "" {
        lblValidationMessage.isHidden = false
        lblValidationMessage.text = "Enter Your Name"
        return
    }

    if let age = txtAge.text, age == "" {
        lblValidationMessage.isHidden = false
        lblValidationMessage.text = "Please enter a numerical age"
        return
    }

    if let email = txtEmail.text, email.isEmpty {
        lblValidationMessage.isHidden = false
        lblValidationMessage.text = "Please enter an email address"
        return
    }

    updateArray()

}

func updateArray(){

    ViewController.firstNames.append(txtfirstName.text!)

    let age:Int! = Int(txtAge.text!)
    ViewController.ages.append(age)

    ViewController.emailAddresses.append(txtEmail.text!)

    txtfirstName.text = ""
    txtAge.text = ""
    txtEmail.text = ""

    txtfirstName.becomeFirstResponder()

    //Checks to see data is being added to the arrays
    print(ViewController.firstNames)
    print(ViewController.ages)
    print(ViewController.emailAddresses)
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

    return ViewController.firstNames.count
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return ViewController.firstNames[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    nameDisplay.text = ViewController.firstNames[row]

    let emailIndex: Int = row
    emailDisplay.text = ViewController.emailAddresses[emailIndex]

    let ageIndex: Int = row
    ageDisplay.text! = String(ViewController.ages[ageIndex])
}

}