Swift:从 TableView 文本字段中检索值

Posted

技术标签:

【中文标题】Swift:从 TableView 文本字段中检索值【英文标题】:Swift: Retrieving values out of TableView Textfields 【发布时间】:2020-04-27 13:56:14 【问题描述】:

我只是试图从我的 TableView 中检索我的所有文本字段值。它适用于 11 个案例中的 10 个。我尝试了以下方法:

    let journeyIDTextField = tableView.cellForRow(at: NSIndexPath(row: 0, section: 1) as IndexPath) as! InputTableViewCell
    journeyID = journeyIDTextField.cellInputTextfield.text!

当我将部分从 1-10 更改为一切正常时,部分 0 会导致错误。 致命错误:在展开可选值时意外发现 nil

因此我尝试查看 IndexPath (0,0) 处是否有文本字段。

    print(section.description, indexPath.row, indexPath.section)
    Result: Description 0 0

所以在 0,0 处肯定有一个文本字段。我不知道该怎么做,尤其是因为它在另一个 ViewController 上运行良好。

有什么想法吗?

最好, 蒂莫

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() 
    cell.cellInputTextfield.placeholder = section.description
    print(section.description, indexPath.row, indexPath.section)

    return cell


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return 1

这是我的牢房: 导入 UIKit

class InputTableViewCell: UITableViewCell 

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)




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"
    




【问题讨论】:

根据您分享的有限信息,很难说。但贴出以下方法:tableView(_:numberOfRowsInSection:)numberOfSections(in:)tableView(_:cellForRowAt:)` 更新了,我的错 【参考方案1】:

我认为一个问题是当 journeyIDTextField.cellInputTextfield.text 等于 nil 时,你会强制解包。我看到的另一个潜在问题是,由于单元格重用,当您滚动时,您的文本字段文本将被擦除。要在重复使用的单元格中正确使用文本字段,请参阅this question。

【讨论】:

【参考方案2】:

您永远不想“从单元格中获取文本”。单元格被重复使用,因此当您滚动 位于 Section: 0 Row: 0 中的文本字段时,现在可能位于 Section: 10 Row: 0 中。

改为在cellForRowAt 中为您的单元格分配一个“回调闭包”。当用户编辑文本字段时,让您的单元格“回调”到控制器以更新数据源。

这是一个完整的示例,您的代码稍作修改:

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
    


当你运行它时,你应该得到:

您可以在字段中输入文本...上下滚动...当您点击“检查数据”按钮时,您将看到枚举属性列表和字段中保存的数据。

【讨论】:

以上是关于Swift:从 TableView 文本字段中检索值的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Swift 中嵌入 UITableView 的文本字段中检索数据?

访问 tableView SWIFT 中的文本字段

从 tableView 上的核心数据填充数据时如何避免行重复

在 swift 中使用 tableview 和数组过滤器自动完成文本字段

如何在 swift 中使文本字段功能在 tableview 中

从表格视图单元格中收集文本字段文本 (Swift)