Search code examples
swiftxcodeuipickerview

Assigning a different output value than what is shown on UIPickerView


I've searched all throughout yesterday on this website for an answer to this, but I haven't been able to find this. I'm an amateur coder, really just doing this for a small organization to see if we can help improve processes.

Here is what I'm trying to do. I'm trying to make an app that allows someone to select an account number, a task, and then it will output a numerical number for a full account number that they can put on receipts.

For example, someone selects account number 12345678910 and they select "cleaning the bathroom". I want the app to spit out a full account number like 12345678910 58392, where 58932 is associated with "cleaning the bathroom", but is not actually shown on the PickerView. I've been having trouble with this. Coding is something I've always wanted to learn, but have been doing it on my own time, so please forgive the amateur like mistakes if any. I've been using YouTube videos for this.

Any help is appreciated. Thanks so much! Sample app screen-shot

import UIKit

class Account {
    var account: String
    var jlCode: [String]

    init(account:String, jlCode:[String]) {
        self.jlCode = jlCode
        self.account = account
    }
}

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {

    @IBOutlet weak var pickerView: UIPickerView!
    @IBOutlet weak var accountLbl: UILabel!

    var accounts = [Account]()

    @IBAction func showPopup(_ sender: Any) {
        let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUpID") as! PopUpViewController
        self.addChildViewController(popOverVC)

        popOverVC.view.frame = self.view.frame
        self.view.addSubview(popOverVC.view)

        popOverVC.didMove(toParentViewController: self)
    }

    override func viewDidLoad() {

        pickerView.delegate = self
        pickerView.dataSource = self

        //This area will have to be changed once you get the right information.

        accounts.append(Account(account: "12345678910", jlCode: ["task 1", "task 2", "task 3", "task 4"]))
        accounts.append(Account(account: "1112131415", jlCode: ["Task 1"]))
        accounts.append(Account(account: "1617181920", jlCode: ["task 1", "task 2", "task 3", "task 4"]))
        accounts.append(Account(account: "2122232425", jlCode: ["task 1", "task 2", "task 3", "task 4"]))

        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

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

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if component == 0 {
            return accounts.count
        } else {
            let selectedAccount = pickerView.selectedRow(inComponent: 0)
            return accounts[selectedAccount].jlCode.count
        }
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if component == 0 {
            return accounts[row].account
        } else {
            let selectedAccount = pickerView.selectedRow(inComponent: 0)
            return accounts[selectedAccount].jlCode[row]
        }
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        pickerView.reloadComponent(1)

        let selectedAccount = pickerView.selectedRow(inComponent: 0)
        let selectedjlCode = pickerView.selectedRow(inComponent: 1)
        let account = accounts[selectedAccount].account
        let jlCode = accounts[selectedAccount].jlCode[selectedjlCode]

        accountLbl.text = "Account Number: \(account)\nJL Code: \(jlCode)"
    }
}

Solution

  • If, and that is a big IF, I understand you correctly your problem is that you have nothing connecting the description of the task with the numeric value associated with the task. In other words it seems your simply struggling with the modelling of your data.

    I would think something like the below might help you in the right direction:

    struct Account {
        var number: Int
        var tasks: [Task]
    
        var description: String { return "\(number)" }
    }
    
    struct Task {
        var number: Int // or JLNumber, or whatever you want to call it
        var description: String
    }
    

    That would leave you setting up Accounts like this:

    let account = Account(number: 12345678910, tasks: [Task(number: 58932, description: "Cleaning the bathroom")])
    

    You would display the .description in the pickerView, and use the .number wherever that makes sense.

    If the different type of tasks are predefined, (i. e. they will never change without the code being changed) you should have a look at enums rather than creating them on the fly with strings and integers...