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

时间:2016-10-07 12:11:20

标签: ios swift uitableview uitextfield

我是一名初级iOS开发人员,而且我已经在一段时间内遇到了问题。

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

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

问题: 我在第一个UITableViewCell和它的UITableView之间来回传输数据时遇到了麻烦。对于文本输入,我在单元类中使用了shouldChangeCharactersInRange方法,然后限制数字的数量并调用tableView类中将比较数据的方法。为此,我使用了代表团。

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

汇总:单元类向tableview类发送数字,tableview类运行的方法,tableview类将bool发送到需要更改出口的单元类。

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

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

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

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() {
}}

实际问题位于&#34;步骤2&#34;。使用这种方法我可以执行print语句,但实际的标签/出口是零,因为它只是一个通用的调用。

任何帮助都会非常感激!谢谢!

2 个答案:

答案 0 :(得分:0)

在你的委托方法中传递你的UITableViewCell实例

func checkNumberInput(senderCell: InputTableViewCell,inputNumber: Int)

然后你就可以在这个单元格的实例上调用任何方法。所以在你的情况下。

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

你可以像

一样调用你的方法
delegate?.checkNumberInput(senderCell: self, inputNumber: numberInput!)

答案 1 :(得分:0)

您也可以使用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)