Как изменить ячейку UITableView из другого ViewController

В VC#1 у меня есть UITableView. Когда я нажимаю на ячейку, я попадаю в VC#2, где отображается информация об этой ячейке.

Я хочу иметь возможность нажимать кнопку в VC#2, которая изменяет заголовок ячейки, которой она соответствует в VC#1, но я не понимаю, как это сделать?

Должен ли я создать переменную в VC#2, чтобы сохранить indexPath для выбранной ячейки, а затем вызвать функцию в VC#1 из VC#2, которая использует этот indexPath для обновления ячейки? Если бы я сделал это, разве VC#1 не должен был быть статичным, чтобы я знал, что изменяю правильный экземпляр VC#1? Я использую push-переход и навигационный контроллер, чтобы вернуться назад, поэтому создание нового экземпляра VC # 1 не будет ссылаться на тот же VC, который я пытаюсь изменить, как я полагаю?

Есть ли более простой способ сделать это?


person Brejuro    schedule 29.01.2018    source источник


Ответы (4)


Вы должны использовать шаблон делегата.

VC1 должен знать, какую ячейку показывает VC2. У вас должно быть свойство IndexPath в VC1, в котором хранится, какая ячейка отображается в данный момент в VC2, верно?

Теперь создайте протокол с именем VC2Delegate:

protocol VC2Delegate : class {
    func titleDidChange(_ vc2: VC2, to title: String)
}

Теперь добавьте это свойство в VC2:

weak var delegate: VC2Delegate?

Теперь, когда вы считаете, что заголовок ячейки должен измениться, вызовите делегата:

delegate?.titleDidChange(self, to: "Some Title")

Это все для VC2.

Приведите VC1 в соответствие с VC2Delegate:

extension VC1: VC2Delegate {
    func titleDidChange(_ vc2: VC2, to title: String) {
        // set the text of the table cell here...
    }
}

Теперь, когда вы передаете данные в VC2 из VC1, вероятно, в методе prepareForSegue, выполните

vc2.delegate = self

Узнайте больше о делегатах здесь.

person Sweeper    schedule 29.01.2018
comment
Я собирался предложить тот же ответ. Ответ хорошо написан! - person Abhishek Harsha; 29.01.2018
comment
@Shebuka VC1 должна иметь эту информацию, когда она собирается представить VC2, не так ли? - person Sweeper; 29.01.2018
comment
@Sweeper Спасибо за это! Один вопрос: когда я реализую метод делегата в VC1, как мне узнать indexPath выбранной ячейки, чтобы я мог обновить заголовок? Я пытался использовать indexPathForSelectedRow, но, похоже, после того, как я перешел к VC2, об этом забыли. - person Brejuro; 29.01.2018
comment
@Brejuro Я полагаю, вы представляете VC2, когда пользователь нажимает на ячейку? Вам нужно объявить свойство IndexPath в VC1 и установить его в методе didSelectRowAt. - person Sweeper; 29.01.2018

Вы можете передавать любые данные, которые хотите, через контроллеры представления, используя делегаты.

Сначала создайте любой протокол

protocol ViewControllerDelegate {

   func getSelected(value:Int)

}

Создайте переменную из ViewController, в которую вы хотите передавать данные

var delegate: ViewControllerDelegate?

В методе didSelectRowAt вы сделаете

if delegate != nil {
   delegate.getSelected(value: indexPath.row)
}

self.navigationController?.popViewController(animated: true)

В ViewController, который будет получать данные, вы должны сделать это

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

   if let vc = segue.destination as? SecondViewController {

      vc.delegate = self

   }

}

extension YourViewController: ViewControllerDelegate {

   fun getSelected(value:Int) {

      // Get value from another view controller and manage it

   } 

}

Этот код находится в Swift 4

Если вы что-то не понимаете, дайте мне знать

person jlima    schedule 29.01.2018

Это неправильный подход, который вы преследуете. Вы должны отделить свой уровень данных от уровня представления. Таким образом, в VC#2 вы редактируете визуализированные данные, а затем VC#1 перезагружает данные, чтобы обновить представление.

person Shebuka    schedule 29.01.2018
comment
Ах, хорошо, но как тогда мне отредактировать ячейку в VC#2? Нужна ли мне ссылка на ячейку или на tableview и indexpath? - person Brejuro; 29.01.2018
comment
Это ваша обязанность как разработчика — спроектировать внутреннюю структуру данных. Как ф.е. массив объектов, и когда вы щелкаете по ячейке VC # 1, он сообщает VC # 2 индекс объекта, затем VC # 2 заполняет его файлами данных из массива, зная его индекс, когда вы обновляете данные, вы передаете уведомление о изменение, и VC#1 обновляет ячейку. - person Shebuka; 29.01.2018

Краткий ответ: Вы не должны этого делать вообще.

Контроллеры представления не должны изменять представления другого контроллера представления.

Вы должны изменить модель данных в VC2, а затем отправить сообщение обратно в VC1 с указанием обновить ячейку.

(В push-переходе вы можете настроить VC1 в качестве делегата VC2, а затем определить протокол, который VC2 использует для уведомления VC1 об indexPath модели данных, которую необходимо обновить.)

person Duncan C    schedule 29.01.2018