(Swift) как передавать данные между UITableView и UITableViewCell?

I’m a beginning iOS developer and i’ve been stuck on an issue for quite some time now.

Фон:
У меня есть один viewcontroller, в котором я разместил TableView (я не могу использовать tableviewcontroller). Он держит 4 динамических клетки прототипа:
Ячейка 1 имеет UITextField и пару меток, ячейка 2-4 имеет только метку (с различными типами информации) и должна быть скрыта изначально.

Когда пользователь вводит номер (макс. 3 цифры) в поле UITextField первой ячейки, число должно быть сравнено, чтобы проверить, является ли оно правильным/существующим числом. Если это число окажется правильным, должно произойти 2 вещи: 1) метки в первой ячейке должны будут изменить макет (цвет, шрифт, размер, …) и установить данные одной метки. 2) другие ячейки в tableview должны появиться под первой ячейкой.

Проблема:
У меня возникли проблемы с отправкой данных между первым UITableViewCell и его UITableView. Для ввода текста я использую метод shouldChangeCharactersInRange в классе cell, который затем ограничивает # цифр и вызывает метод в классе tableView, где будут сравниваться данные. Для этого я использовал делегирование.

Тем не менее, после проверки, соответствует ли номер, мне нужно вызвать метод в классе ячейки (из класса tableview), который изменит макет и установит данные метки в ячейке. Тем не менее, я не могу найти способ заставить этот метод вызова работать и получить доступ к выходам.

Summarised: cell class передает номер в TableView class, методы в TableView class run, tableview class передает 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() {
}}

Актуальная задача находится в «шаге 2». Используя этот метод, я могу выполнить инструкцию print, но фактические метки/выходы равны нулю, потому что это просто общий вызов.

Любая помощь будет безмерно признательна! Спасибо!

2 ответа

  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)