2017-09-21 18 views
0

フォームのように、UITableViewCellの入力をいくつか入力する必要があるアプリケーションを作成しています。デキューする前にUITableViewCellでユーザー入力を保持する方法

func doneButtonTapped() { 

    var dict = [String: Any]() 

    for rows in 0...TableViewCells.getTableViewCell(ceilingType: node.ceilingSelected, moduleType: node.moduleSelected).count { 

     let ip = IndexPath(row: rows, section: 0) 

     let cells = tableView.cellForRow(at: ip) 

     if let numericCell = cells as? NumericInputTableViewCell { 

      if let text = numericCell.userInputTextField.text { 

       dict[numericCell.numericTitleLabel.text!] = text 
      } 

     } else if let booleanCell = cells as? BooleanInputTableViewCell { 

      let booleanSelection = booleanCell.booleanToggleSwitch.isOn 
      dict[booleanCell.booleanTitleLabel.text!] = booleanSelection 
     } 
    } 

    let calculator = Calculator(userInputDictionary: dict, ceiling_type: node.ceilingSelected) 
} 

:ユーザーが実行ボタンをタップすると、私は別のビューコントローラ

にいくつかの計算と出力それらを実行することができますので、これらの入力を収集する必要がありますここで私はこれらの入力を収集するために使用される方法であります私が抱えている問題は、セルが見えなくなり、ユーザーの入力がメモリからクリアされたときです。あなたが見ることができるように、すべてのセルが表示されたら、

enter image description here

は、行わボタンは、コンソールの印刷から明らかに、ユーザーからのすべての入力を保存するための管理:ここに私のポイントを説明するための2つのスクリーンショットです。細胞は視野の外にある場合には、面積/㎡からの入力はnilに設定されています

enter image description here

心に来た解決策は、私がそうであるように、私がデキュー可能なセルを使用するべきではありませんでした見えないときにセルをメモリに入れたいが、スタックオーバーコミュニティの多くはこのプラクティスに対して強い。この問題をどのように解決すればよいですか?ありがとう!

UPDATE

コードcellForRow(at: IndexPath)

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

     guard let node = node else { 
      return UITableViewCell() 
     } 

     let cellArray = TableViewCells.getTableViewCell(ceilingType: node.ceilingSelected, moduleType: node.moduleSelected) 

     switch cellArray[indexPath.row].cellType { 

     case .numericInput : 

      let cell = tableView.dequeueReusableCell(withIdentifier: "numericCell", for: indexPath) as! NumericInputTableViewCell 
      cell.numericTitleLabel.text = cellArray[indexPath.row].title 
      return cell 

     case .booleanInput : 

      let cell = tableView.dequeueReusableCell(withIdentifier: "booleanCell", for: indexPath) as! BooleanInputTableViewCell 
      cell.booleanTitleLabel.text = cellArray[indexPath.row].title 
      return cell 

     } 
    } 
} 

私の2つのカスタムセル

NumericInputTableViewCell

class NumericInputTableViewCell: UITableViewCell { 

    @IBOutlet weak var numericTitleLabel: UILabel! 

    @IBOutlet weak var userInputTextField: UITextField! 

} 

BooleanInputTableViewCell

​​

任意の受験者?

+0

あなたが辞書を記入している間に辞書を記入してみませんか?次に、テーブルにではなく辞書にすべてのデータを格納します(推奨されません)。 – GIJOW

+0

デリゲートを使用して、データをdict(データソース)に戻します。セルは再利用されているため、セルの表示データに依存したくありません。 – HMHero

+1

@GIJOWと合意してください。言い換えれば、ビューはデータモデルの代用として使用すべきではありません。 –

答えて

0

テーブルビューはセルを再利用するため、通常、データがテーブルビューセルの一部のコンポーネントに依存する場合は適切ではありません。それどころか、それは逆になるはずです。あなたのケースでユーザ入力データが提供される前であっても、テーブルビューデータは常にテーブルビューのセルのコンポーネントを駆動します。

  • 初期データ - あなたのコードのどこかに既にあるはずです。私はあなたの提供、コードビューコントローラで

    let data = CellData() 
        data.title = "Troffer Light Fittin" 
        data.value = false 
    
        let data2 = CellData() 
        data2.title = "Length Drop" 
        data2.value = "0" 
    
        cellData.append(data) 
        cellData.append(data2) 
    
  • enum CellType { 
        case numericInput, booleanInput 
    } 
    
    class CellData { 
        var title: String? 
        var value: Any? 
    
        var cellType: CellType { 
         if let _ = value as? Bool { 
          return .booleanInput 
         } else { 
          return .numericInput 
         } 
        } 
        } 
    
    protocol DataCellDelegate: class { 
        func didChangeCellData(_ cell: UITableViewCell) 
    } 
    
    class DataTableViewCell: UITableViewCell { 
        var data: CellData? 
        weak var delegate: DataCellDelegate? 
    } 
    
    class NumericInputTableViewCell: DataTableViewCell { 
    
    let userInputTextField: UITextField = UITextField() 
    
    override var data: CellData? { 
        didSet { 
         textLabel?.text = data?.title 
         if let value = data?.value as? String { 
          userInputTextField.text = value 
         } 
        } 
    } 
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
        super.init(style: style, reuseIdentifier: reuseIdentifier) 
    
        userInputTextField.addTarget(self, action: #selector(textDidChange(_:)), for: .editingChanged) 
        contentView.addSubview(userInputTextField) 
    } 
    
    required init?(coder aDecoder: NSCoder) { 
        fatalError("init(coder:) has not been implemented") 
    } 
    
    func textDidChange(_ textField: UITextField) { 
        //update data and let the delegate know data is updated 
        data?.value = textField.text 
        delegate?.didChangeCellData(self) 
    } 
    //Disregard this part 
    override func layoutSubviews() { 
        super.layoutSubviews() 
        textLabel?.frame.size.height = bounds.size.height/2 
        userInputTextField.frame = CGRect(x: (textLabel?.frame.origin.x ?? 10), y: bounds.size.height/2, width: bounds.size.width - (textLabel?.frame.origin.x ?? 10), height: bounds.size.height/2) 
    } 
    } 
    
    class BooleanInputTableViewCell: DataTableViewCell { 
    
    override var data: CellData? { 
        didSet { 
         textLabel?.text = data?.title 
         if let value = data?.value as? Bool { 
          booleanToggleSwitch.isOn = value 
         } 
        } 
    } 
    
    let booleanToggleSwitch = UISwitch(frame: .zero) 
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
        super.init(style: style, reuseIdentifier: reuseIdentifier) 
    
        booleanToggleSwitch.addTarget(self, action: #selector(toggled), for: .valueChanged) 
        booleanToggleSwitch.isOn = true 
        accessoryView = booleanToggleSwitch 
        accessoryType = .none 
        selectionStyle = .none 
    
    } 
    
    func toggled() { 
        //update data and let the delegate know data is updated 
        data?.value = booleanToggleSwitch.isOn 
        delegate?.didChangeCellData(self) 
    } 
    
    required init?(coder aDecoder: NSCoder) { 
        fatalError("init(coder:) has not been implemented") 
    } 
    } 
    
  • から自分自身を作成し​​、あなたがあなたの元のデータソースを更新する必要がありますが、テーブルビューをスクロールするときに、データソースは、右のINFOMATIONをprivide 。要するに

    func didChangeCellData(_ cell: UITableViewCell) { 
        if let cell = cell as? DataTableViewCell { 
         for data in cellData { 
          if let title = data.title, let titlePassed = cell.data?.title, title == titlePassed { 
            data.value = cell.data?.value 
          } 
         } 
        } 
    
        for data in cellData { 
         print("\(data.title) \(data.value)") 
        } 
    } 
    
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
         return cellData.count 
        } 
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        let data = cellData[indexPath.row] 
        let cell: DataTableViewCell 
        if data.cellType == .booleanInput { 
         cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(BooleanInputTableViewCell.self), for: indexPath) as! BooleanInputTableViewCell 
        } else { 
         cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(NumericInputTableViewCell.self), for: indexPath) as! NumericInputTableViewCell 
        } 
        cell.data = cellData[indexPath.row] 
        cell.delegate = self 
        return cell 
    } 
    

、テーブルビューのための単一のデータソースを持っているとバックデータソースへのセルで更新されたデータを渡すために、デリゲートを使用するようにしてください。

レイアウトに関することは何も無視してください。あなたの要件をテストするためにストーリーボードを使用しませんでした。

+0

うわー、これは本当にありがとう!!私はそれを試してみると、戻ってくる!非常に私の助けにあなたの努力を感謝! –

+0

私はあなたのアプローチを実装する過程にあります。私のView Controllerがプロトコルに準拠しているとき、デリゲートをどこで 'self'に設定すればいいですか? 'cellForRow'メソッドで?ありがとう –

+0

私の例では、はい。 – HMHero

1

私は他の寄稿者に同意します。細胞をデータ保存に使用すべきではありません。別のアプローチ(例えば、HMHeroが示唆するもの)を考慮する必要があります。

しかし、あなたの質問は、それが削除される前のUITableViewCellにアクセスする方法についてもあったように、あなたはそのために使用することができますUITableViewDelegateでの方法があります:

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { 
    // do something with the cell before it gets deallocated 
} 

このメソッドは、そのデリゲートを伝えます指定されたセルがテーブルから削除されました。だから、それが消える前にその細胞で何かをする最後のチャンスを与えます。

関連する問題