Swift: Retrieving values out of TableView Textfields

后端 未结 2 1867
隐瞒了意图╮
隐瞒了意图╮ 2021-01-27 12:37

I just tried to retrieve all my textfield values out of my TableView. It worked for 10 of 11 cases. I tried the following:

    let journeyIDTextField = tableView         


        
相关标签:
2条回答
  • 2021-01-27 13:09

    I think one issue is that you're force unwrapping journeyIDTextField.cellInputTextfield.text when it equals nil. One other potential issue I see is that your textfield text will get wiped when you scroll due to cell reuse. For properly using a textfield in a reused cell, see this question.

    0 讨论(0)
  • 2021-01-27 13:24

    You never want to "get text from a cell". Cells are reused, so when you scroll the text field that was in Section: 0 Row: 0 may now be in Section: 10 Row: 0 .

    Instead, assign a "callback closure" to your cell in cellForRowAt. When the user edits the text field, have your cell "call back" to the controller to update the data source.

    Here is a complete example, with your code slightly modified:

    class InputTableViewCell: UITableViewCell {
    
        // callback closure to tell the controller the text field was edited
        var callback: ((String) ->())?
    
        let cellInputTextfield: UITextField = {
            let cellInputTextfield = UITextField()
            cellInputTextfield.textColor = .black
            cellInputTextfield.sizeToFit()
            return cellInputTextfield
        }()
    
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: .default, reuseIdentifier: reuseIdentifier)
    
            cellInputTextfield.frame = CGRect(x: 20, y: 0, width: self.frame.width, height: 60)
            cellInputTextfield.font = UIFont.systemFont(ofSize: 15)
            self.contentView.addSubview(cellInputTextfield)
    
            // add a target func to call when the text field is edited
            cellInputTextfield.addTarget(self, action: #selector(textFieldChanged(_:)), for: .editingChanged)
        }
    
        @objc func textFieldChanged(_ textField: UITextField) -> Void {
            // end the edited text back to the controller
            callback?(textField.text ?? "")
        }
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    enum JourneySection:Int, CaseIterable, CustomStringConvertible{
        case Description
        case ID
        case Confirmation
        case Destination
        case DestinationDate
        case DestinationTime
        case Arrival
        case ArrivalDate
        case ArrivalTime
        case PriceTotal
        case Companions
    
    
        var description: String {
            switch  self {
            case .Description: return "Description"
            case .ID: return "ID f.ex. Flight Number"
            case .Confirmation: return "Confirmation No."
            case .Destination: return "Destination"
            case .DestinationDate: return "Destination Date, like DD-MM-YYYY"
            case .DestinationTime: return "Destination Time, like hh-mm"
            case .Arrival: return "Arrival"
            case .ArrivalDate: return "Arrival Date, like DD-MM-YYYY"
            case .ArrivalTime: return "Arrival Time, like hh-mm"
            case .PriceTotal: return "Total Price"
            case .Companions: return "No. Of Companions"
            }
    
        }
    
    }
    
    class JourneyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
        let testButton: UIButton = {
            let v = UIButton()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.setTitle("Check Data", for: [])
            v.setTitleColor(.white, for: [])
            v.backgroundColor = .red
            return v
        }()
    
        let tableView: UITableView = {
            let v = UITableView()
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
    
        let reuseIdentifierInputCell = "journeyCell"
    
        // declare a string data array
        var dataStrings: [String] = [String]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // initialize the data array with an empty string for each case
            // in actual use, you may have already populated "saved" data
            dataStrings = Array(repeating: "", count: JourneySection.allCases.count)
    
            // add the button and table view
            view.addSubview(testButton)
            view.addSubview(tableView)
    
            // respect safe area
            let g = view.safeAreaLayoutGuide
    
            NSLayoutConstraint.activate([
    
                // constrain the button to Top: 20-pts and centered horizontally
                testButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
                testButton.centerXAnchor.constraint(equalTo: g.centerXAnchor),
    
                // constrain the tableview to 8-pts below the button
                // Leading / Trailing at 20-pts
                // with a height of 240 (so we can see what happens when scrolling)
                tableView.topAnchor.constraint(equalTo: testButton.bottomAnchor, constant: 8.0),
                tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
                tableView.heightAnchor.constraint(equalToConstant: 240.0),
    
            ])
    
            // register the cell class
            tableView.register(InputTableViewCell.self, forCellReuseIdentifier: reuseIdentifierInputCell)
    
            // set dataSource and delegate
            tableView.dataSource = self
            tableView.delegate = self
    
            // dismiss keyboard when table scrolls
            tableView.keyboardDismissMode = .onDrag
    
            testButton.addTarget(self, action: #selector(showData(_:)), for: .touchUpInside)
        }
    
        @objc func showData(_ sender: UIButton) -> Void {
            for i in 0..<JourneySection.allCases.count {
                guard let section = JourneySection(rawValue: i) else {
                    fatalError("Something wrong with JourneySection")
                }
                print(section.description, ":", dataStrings[i])
            }
        }
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return JourneySection.allCases.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifierInputCell, for: indexPath) as! InputTableViewCell
    
            guard let section = JourneySection(rawValue: indexPath.section) else { return UITableViewCell() }
    
            // set placeholder
            cell.cellInputTextfield.placeholder = section.description
    
            // set the cell's text field's text
            // if this entry in our data source is "", the placeholder will be shown
            cell.cellInputTextfield.text = dataStrings[indexPath.section]
    
            // we want the cell to "call us back" when the textfield is edited
            cell.callback = { str in
                // update our data source
                self.dataStrings[indexPath.section] = str
            }
    
            return cell
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1
        }
    
    }
    

    When you run it, you should get:

    You can enter text in the fields... scroll up and down... and when you tap the "Check Data" button you'll see your list of enum properties and the saved data from the fields.

    0 讨论(0)
提交回复
热议问题