(Swift) 如何在 UITableView 和 UITableViewCell 之间来回传递数据?

Posted

技术标签:

【中文标题】(Swift) 如何在 UITableView 和 UITableViewCell 之间来回传递数据?【英文标题】:(Swift) How to pass data back and forth between UITableView and UITableViewCell? 【发布时间】:2016-10-07 12:11:19 【问题描述】:

我是一名初级 ios 开发人员,我已经被一个问题困扰了很长一段时间了。

背景: 我有一个视图控制器,其中放置了一个 TableView(我不能使用 tableviewcontroller)。它拥有 4 个动态原型单元: 单元格 1 有一个 UITextField 和几个标签,单元格 2-4 只有一个标签(带有不同类型的信息),并且最初必须隐藏。

当用户在第一个单元格的 UITextField 中输入一个数字(最多 3 位)时,必须比较该数字以检查它是否是正确/现有的数字。如果这个数字被证明是正确的,则必须发生两件事:1)第一个单元格中的标签需要更改布局(颜色、字体、大小……)并设置一个标签的数据。 2) 表格视图中的其他单元格必须出现在第一个单元格下方。

问题: 我在第一个 UITableViewCell 和它的 UITableView 之间来回发送数据时遇到问题。对于文本输入,我使用 cell 类中的 shouldChangeCharactersInRange 方法,然后限制数字的数量并调用 tableView 类中的方法来比较数据。为此,我使用了委托。

但是,在检查数字是否匹配后,我需要调用单元格类中的一个方法(从 tableview 类中),该方法将更改布局并设置单元格中标签的数据。然而我似乎无法找到一种方法来使这个方法调用工作并访问出口。

总结: cell 类向 tableview 类发送数字,tableview 类中的方法运行,tableview 类将 bool 发送到需要更改 outlet 的 cell 类。

我尝试了什么: 我尝试在另一个方向设置委托,但它不会触发。使用普通的方法调用也不行,因为出口为零。

我认为我的问题在于我需要引用单元的相同实例/对象来访问网点?

我选择并简化了相关的代码:

1) TableView 类

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, updateUITableView 

var existingNumber = 200
var cellsRowHeight = false

@IBOutlet var tableView: UITableView!

//Started by InputTableViewCell when UITextField has a 3 digit-number
func checkNumberInput(inputNumber: Int) 
    //Step 1: check if the number matches an existing one
    let match = checkNumberMatch(inputNumber: inputNumber)

    //Step 2: send a bool back to the cell class to change the layout through outlets
    InputTableViewCell().changeLayout(numberMatch: match) // <--- problem

    //Step 3: make the hidden cells appear
    toggleCellsVisibility(numberMatch: match)


//Step 1
func checkNumberMatch(inputNumber: Int) -> Bool 
    if inputNumber == existingNumber 
        return true
     else 
        return false
    


//Step 2
func toggleCellsVisibility(numberMatch: Bool) 
    cellsRowHeight = numberMatch
    if numberMatch == true  //cells appear
        tableView?.beginUpdates()
        tableView?.endUpdates()
        //possible additional code
     else  //cells dissappear
        tableView?.beginUpdates()
        tableView?.endUpdates()
        //possible additional code
    


//Step 3
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    switch (indexPath.row) 
    case 0 where !cellsRowHeight || cellsRowHeight:
        return 170
    case 1 where !cellsRowHeight:
        return 0
    case 1 where cellsRowHeight:
        return 54
    //cases for other cells to appear/dissappear
    default:
        return 44
    


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    if indexPath.row == 0 
        //Create tableViewCell
        let cellIdentifier = "InputCell"
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! InputTableViewCell

        cell.delegate = self

        //Customize lay-out of cell
        cell.preservesSuperviewLayoutMargins = false
        cell.separatorInset = UIEdgeInsets.zero
        cell.layoutMargins = UIEdgeInsets.zero

        return cell
    
    //creation of other cells


// MARK: - Loading
override func viewDidLoad() 
    super.viewDidLoad()
    tableView.tableFooterView = UIView(frame: CGRect.zero)

2) 单元类:

protocol updateUITableView: class 
func checkNumberInput(inputNumber: Int)


class InputTableViewCell: UITableViewCell, UITextFieldDelegate 
var delegate: updateUITableView?

@IBOutlet var textField: UITextField!
@IBOutlet var letterLabel: UILabel!

//Step 2: problem!
func changeLayout(numberMatch: Bool) 
    if numberMatch == true 
        print("Success") //this line triggers
        letterLabel?.text = "A" //is nil
        //other lay-out changes
    
    else 
        print("Fail, please provide an existing number")
        //other lay-out changes
    


//Set maximum character limit in textField and dismiss keyboard when character limit is reached.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
    let currentCharacterCount = textField.text?.characters.count ?? 0
    let newLength = currentCharacterCount + string.characters.count - range.length

    if (newLength == 3) 
        textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string)

        //Get text from textField
        let numberInput: Int? = Int(textField.text!)
        if numberInput != nil 
            delegate?.checkNumberInput(number: numberInput!) //send number to tableview class
        
        //Dismiss keyboard
        textField.resignFirstResponder()

        if (range.length + range.location > currentCharacterCount) 
            return false
         else 
            return true
        
    
    return true


func viewDidLoad() 

实际问题位于“步骤 2”。使用这种方法我可以执行打印语句,但实际的标签/插座是 nil,因为它只是一个通用调用。

任何帮助将不胜感激!谢谢!

【问题讨论】:

【参考方案1】:

像这样在您的委托方法中传递您的 UITableViewCell 实例

func checkNumberInput(senderCell: InputTableViewCell,inputNumber: Int)

然后您将能够调用此单元格实例上的任何方法。所以在你的情况下。

func checkNumberInput(senderCell: InputTableViewCell,inputNumber: Int)
//...
   senderCell.changeLayout(numberMatch: match) 
//....

你可以像这样调用你的方法

delegate?.checkNumberInput(senderCell: self, inputNumber: numberInput!)

【讨论】:

【参考方案2】:

您也可以使用 NSNotificationCenter 传递数据。

把这段代码放到viewDidLoad中

NotificationCenter.default.addObserver(self, selector: #selector(receivedDataFromNotification(notification:)), name: NSNotification.Name(rawValue: "receiveData"), object: nil)

这个通知选择器方法

func receivedDataFromNotification(notification : NSNotification) -> Void 

然后在需要传递数据时发布通知。

  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "receiveData"), object: YourObject)

【讨论】:

以上是关于(Swift) 如何在 UITableView 和 UITableViewCell 之间来回传递数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中为 UITableView 设置左右边距

如何在 Swift 3 中以编程方式在 UIImageview 中添加 UITableview

Swift:如何在动态 UITableView 的自定义单元格中获取滑块的值?

如何在 Swift 中使用搜索栏过滤具有自定义单元格的 UITableView 的内容?

如何初始加载 UITableView 然后观察 Firebase 节点以更改在 Swift 中刷新 tableview?

Swift3,如何在不同的 viewController 中使用相同的 UITableView