Передача данных при нажатии на Cell в DetailTableView


#1

Всем привет! Такой вопрос, реализована таблица, которая заполняется в одном ViewController, затем при нажатии на ячейку таблицы открывается TableViewController, который является по сути и Detail окном и Edit окном в котором Static cells и в котором находятся Label, которые не изменяются и поля TextField в которые передаются данные из TableView

Вопрос в том, что когда заполняю TableView:

То при нажатии на ячейку данные в DetailTableView не меняются (нажата ячейка с “123”):

image

И не совсем представляю, как можно реализовать редактирование, т.е. я меняю текст в Detail, нажимаю “Сохранить” и чтобы он менялся в главном TableView

Код DetailTableView:

import UIKit

protocol EditCableDelegate {
func sendChangeCable(_ sendCable: DetailCableTableViewController, didChangeCable cable: Cable)
}

class DetailCableTableViewController: UITableViewController, UITextFieldDelegate {

@IBOutlet var DetailTable: UITableView!
@IBOutlet var NameTextField: UITextField!
@IBOutlet var LengthTextField: UITextField!
@IBOutlet var RTextField: UITextField!
@IBOutlet var XTextField: UITextField!

var detailCable = [Cable]()

var delegateChange: EditCableDelegate?

override func viewDidLoad() {
    super.viewDidLoad()
    DetailTable.reloadData()
    insertText()
    }

func insertText() {
    for (index, _) in detailCable.enumerated() {
        let detail = detailCable[index]
        NameTextField.text = detail.NameOfCable
        LengthTextField.text = detail.LengthOfCable
        RTextField.text = detail.RCable
        XTextField.text = detail.XCable
}
}


@IBAction func Save(_ sender: UIBarButtonItem) {

    let NameOfCable = String(NameTextField.text!)
    let LengthOfCable = String(LengthTextField.text!)
    let RCable = String(RTextField.text!)
    let XCable = String(XTextField.text!)
        
    let newCables = Cable(NameOfCable: NameOfCable, LengthOfCable: LengthOfCable, RCable: RCable, XCable: XCable)
        
   delegateChange?.sendChangeCable(self, didChangeCable: newCables)
    
    dismiss(animated: true, completion: nil)
}

@IBAction func Cancel(_ sender: UIBarButtonItem) {
    dismiss(animated: true, completion: nil)
}
}

Вот в таком виде передаются данные из TableView:

image


#2

В основном контроллере вы подписались под протокол ?


#3

Да :slight_smile:

func sendChangeCable(_ sendCable: DetailCableTableViewController, didChangeCable cable: Cable) {
    cables.append(cable)
    CableTable.reloadData()
}

Может ли иметь проблемы то, что у меня два разных протокола обращаются к одной переменной ?

func sendDataCable(_ sendCable: AddCableViewController, didAddCable cable: Cable) {
    cables.append(cable)
    CableTable.reloadData()
}

вот еще один протокол с другого контроллера


#4

Вам не нужен массив на странице редактирования: var detailCable = [Cable](), оставьте один кабель: var detailCable: Cable!. Сейчас в функции insertText() вы циклом всегда берёте последнее значение массива, поэтому данные неверно отображаются.

Небольшое замечание по циклу

Вместо этой двухступенчатой формы:

for (index, _) in detailCable.enumerated() {
        let detail = detailCable[index]

Можно было просто вытаскивать экземпляры из массива: for cable in detailCable {}

Если в func sendChangeCable у вас будет индекс, то проблема редактирования будет решена:

if let index = CableTable.indexPathForSelectedRow?.row {
    cables[index] = cable
    ..reloadCell..
}

Если нет, то можно передавать индекс на страницу редактирования и обратно. Или в том случае, если Cable - class (ссылочный тип), вы не создаёте newCable в Save(), а меняете поля detailCable, а при возвращении ничего не передаёте и перегружаете таблицу.


#5

Спасибо! У меня вот как раз Cable - это отдельный класс. Но вот не совсем понял, как будет реализовываться изменение полей в detailCable, которые передаются в tableView другого контроллера


#6

Примерно так:

@IBAction func Save(_ sender: UIBarButtonItem) {
detailCable.NameOfCable = NameTextField.text
....
delegateChange?.sendChangeCable()
dismiss(animated: true, completion: nil)
}

В sendChangeCable() у вас просто CableTable.reloadData().

То есть вы меняете свойства класса, а из-за того, что detailCable ссылается на экземпляр, который содержится в массиве cables у родительского VC, то там эти изменения тоже произойдут. Вам не надо его “передавать” обратно. Но, насколько я понимаю, это не очень хорошая практика; лучше будет вытащить индекс у таблицы.

PS Вам нужно обратить внимание на использование прописных букв в наименованиях.


#7

Я примерно так и сделал, только вот проблемка вылезла в том, что данные сохраняются и при нажатии на ячейку таблицы показываются измененные данные, но вот прикол в том, что, если меняю наименование, это то, что отображается в tableView, то они в detailView показываются измененными, а в tableView - нет, они обновляются только после того, как я добавлю следующий элемент в tableView… Я пробовал ставить breakpoint в месте, где подписываю ViewController с TableView и такое впечатление, что он не вызывает его


#8

Посмотри видео Что такое делегирование
Может упустил что!


#9

имхо возможно вам стоит подумать об упрощении архитектуры приложения в целом. Вы выводите на один экран сразу три разные таблицы. Такой style больше подходит для офисных программ, в мобильном приложении style несколько другой.

Рассмотрите возможность использовать Tab Bar Controller, положить на каждую вкладку отдельную таблицу в готовом TVC, и для каждой из них сделать свой отдельный Detail. Технически это будет гораздо проще, например отпадет масса работы с делегатами.

У меня был похожий опыт, когда пытался положить все на один экран, типа для удобства пользователя. Потратил на это достаточное количество времени, но чем дальше, тем становилось сложнее. Казалось вот-вот, осталось совсем немного, но потом оказывалось, что для того, чтобы сделать какую-то мелочь приходилось тратить очень много времени. А рядом, в стандартном решении практически все эти мелочи есть готовые. Понимаю, что это непростое решение, повернуть, когда уже столько сделано, но по своему опыту знаю, что в конечно итоге это все равно будет быстрее. Плюс добавьте сюда качество кода.


#10

Спасибо за совет !) я вот главный экран уже доделал, остался крайний page view controller с математикой за бортом выводом результатов и дело сделано, но на будущее буду делать, как вы советуете )


#11

я тоже так думал)), причем несколько раз))

На мой взгляд ваш код перегружен. Цикл там явно не нужен, протоколы и делегаты тоже под сомнением. Обычно достаточно просто передать по сигвею значения и обычным стандартным способом присвоить их в нужные ярлыки или текстфилды.

Но если это работает, то без проблем!))

P.S. У таких таблиц 4 типовые задачи - просмотреть существующий элемент, добавить новый элемент, редактировать существующий элемент и удалить существующий элемент. Первые три выполняются в Detail, последняя в основной таблице.

Заодно проверьте, если открывается таблица для добавления нового элемента и сразу без данных нажимается кнопка Сохранить.