簡體   English   中英

從筆尖初始化自定義UITableViewCell而不使用dequeueReusableCellWithIdentifier

[英]Init custom UITableViewCell from nib without dequeueReusableCellWithIdentifier

迅速

我需要制作一個單元格數組。 我有一些帶有nib文件的自定義單元格類(從UITableViewCell繼承)。

如何初始化單元格而不在表視圖中注冊nib並執行dequeueReusableCellWithIdentifier? 我是這樣做的,但不認為它會起作用:

var labelCell = CustomCellClass.initialize()

從其他地方的討論中可以推斷出,您不希望讓單元出隊和重復使用的原因是,您無法跟蹤在單元中捕獲的用戶輸入。

最重要的是,您實際上應該允許對單元進行出隊和重用,並進行適當的處​​理。 如果您在重復使用單元格時遇到問題,可以通過將“模型”(即數據)與“視圖”(即UIKit控件)分開來解決。 這是模型-視圖-控制器模式的精神,但在所有具有關注點分離的模式(例如MVVP,MVP等)中都是如此。

關鍵是,隨着單元格中值的更改,您的單元格應立即告知視圖控制器,以便視圖控制器可以立即更新模型。 然后,當視圖控制器以后需要對與特定行相關聯的值進行某些操作時,它不會從單元格中檢索到它,而是從其自己的模型中檢索到它。

因此,我可以為單元格定義一個協議,以通知表視圖其文本字段已更改:

protocol CustomCellDelegate: class {
    func cell(_ cell: CustomCell, didUpdateTextField textField: UITextField)
}

然后,我將定義一個調用該委托的單元格類:

class CustomCell: UITableViewCell {
    weak var delegate: CustomCellDelegate?

    @IBOutlet weak var customTextField: UITextField!          // hook up outlet to this property in IB

    @IBAction func didChangeValue(_ sender: UITextField) {      // hook up "editing changed" action for the text field to this method in IB
        delegate?.cell(self, didUpdateTextField: sender)
    }
}

現在,視圖控制器將:

  • 在相關的NIB中注冊重用標識符;
  • cellForRowAt ,填充文本字段並將其自身指定為該單元格的委托;
  • 如果用戶更改了任何內容,請處理didUpdateTextField方法以更新模型。

因此,類似:

class ViewController: UITableViewController {

    var values = ["One", "Two", "Three"]  // some initial values

    private let cellIdentifier = "CustomCell"

    override func viewDidLoad() {
        super.viewDidLoad()

        // if you’re using NIBs, you register them. 
        // obviously if using prototype cells in your storyboard, this isn’t necessary.

        tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: cellIdentifier) // or use cell prototype with storyboard identifer specified
    }
}

// MARK: - UITableViewDataSource

extension ViewController {

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return values.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CustomCell

        // populate cell and specify delegate

        cell.delegate = self
        cell.customTextField.text = values[indexPath.row]

        return cell
    }
}

// MARK: - CustomCellDelegate

extension ViewController: CustomCellDelegate {
    func cell(_ cell: CustomCell, didUpdateTextField textField: UITextField) {
        // when the cell tells us that its text field's value changed, update our own model

        if let indexPath = tableView.indexPath(for: cell), let string = textField.text {
            values[indexPath.row] = string
        }
    }
}

通過將文本字段的IBAction直接掛鈎到視圖控制器方法,許多人可能傾向於進一步簡化此操作。 這行得通,並且消除了對該協議的需求,但是問題是您需要弄清楚該特定UIKit控件與哪一行相關聯。 常見的技巧是在視圖層次結構中向上導航以標識適當的單元格(例如,文本字段通常位於該單元格中的內容視圖中,因此您將textField.superview.superview as! UITableViewCell ),但這感覺有點脆弱對我來說。

但是,不管有這么小的細節,希望它能說明更廣泛的模式。 與其嘗試使單元格跟蹤用戶輸入,不如讓單元格(“視圖”)立即更新任何數據更改的控制器,然后視圖控制器立即更新模型,而您不再需要擔心iOS使用的單元重用優化。

對於Swift 2演繹版本,請參見此答案的先前版本

靜態表的基本思想是在IB中對其進行完全定義。 一種解決方案是將這些單元格從其隔離的NIB復制粘貼到包含表格的單元格中。

更好的解決方案是使表動態化,並使動態代碼返回靜態數目的節和行。 編寫其余邏輯,就好像它是動態的一樣(例如,注冊所有筆尖,並按照您希望它們在表中的組織方式初始化單元格標識符數組,使用該數組出隊)。

解決它的另一種方法:

1)視圖控制器中的UITextField委托。 將值存儲在數組中

var textFieldValues = ["", "", "", "", "", "", "", "", "", ""] // with count of text fields in table. Init in top of ViewController.

//MARK:TextField Delegate

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if string == " "
    {
        return false
    }

    let indexPathForCellWhereTextFieldIs = self.tableView.indexPathForCell(textField.superview?.superview as! UITableViewCell)
    textFieldValues[(indexPathForCellWhereTextFieldIs?.section)!] = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string) as NSString as String

    return true
}

2)在indexPathForRow

    cell.registrationTextField.text = textFieldValues[indexPath.section]
    cell.registrationTextField.delegate = self

3)從數組中獲取數據

func tapOnRegisterButton(sender:UIButton)
{
    debugPrint(textFieldValues)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM