Привет, Эвелин! Используйте шаблон делегирования! :)
Вот несколько пояснений, которые помогут вам продолжать:
- создать модель для представления содержимого вашего табличного представления
Какого родамодели мы могли бы использовать, чтобы представить состояние, когда выбрана только одна кнопка? Перечисление может представлять это (добавить его в отдельный файл или в ваш контроллер):
enum ButtonSelectionIdentity {
case first
case second
case third
}
В нашем табличном представлении будет представлен массив этих перечислений, в контроллере, давайте добавим переменную экземпляра вудерживайте данные и инициализируйте их пустым массивом:
private var elements: [ButtonSelectionIdentity] = []
Давайте заполним этот массив 100 элементами, по умолчанию выбирая первую кнопку в функции контроллера viewDidLoad, добавив:
for i in 0..<100 {
elements.append(ButtonSelectionIdentity.first)
}
убедитесь, что ячейки обновлены из модели
Итак, теперь у нас есть модель (массив ButtonSelectionIdentity
), и мы хотим, чтобы контроллер табличного представления отражал эту модель. Для этого мы изменим первоначальный способ соответствия контроллера UITableViewDataSource
. Нам нужна новая реализация для получения данных из массива:
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? Cell else {
return UITableViewCell()
}
let model = elements[indexPath.row]
cell.update(with: model)
return cell
}
}
Да, после изменения, указанного выше, оно не скомпилируется, пока мы не добавим метод обновления в класс ячейки:
func update(with model: ButtonSelectionIdentity) {
btn1.backgroundColor = .blue
btn2.backgroundColor = .blue
btn3.backgroundColor = .blue
switch model {
case .first:
btn1.backgroundColor = .red
case .second:
btn2.backgroundColor = .red
case .third:
btn3.backgroundColor = .red
}
}
Скомпилируйте и запустите, вы должны увидеть 100 клеток с первым квадратом красного цвета.
Позволяет связать действия ячеек с контроллером
Удалите метод buttonSelected
из вашего класса контроллера и удалите метод btnTypeSelected
из вашего класса Cell, чтобы мы могли начать все сначала. .
На этом этапе у нас есть массив элементов, представленных в табличном представлении внутри контроллера. Контроллер владеет им, потому что он его создал. Ячейки предназначены только для представления состояния, которое имеет контроллер. Итак, чтобы заставить нашу ячейку обновляться, мы должны сообщить контроллеру, что мы обновляем. Для этого мы можем использовать шаблон делегирования. Давайте создадим протокол делегата ячейки для его описания.
В вашем файле класса Cell
перед class Cell ...
добавьте:
protocol CellDelegate: class {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity)
}
Так что это тот делегат, который мы будем использовать длясообщите контролеру об изменении состояния в ячейке. Добавим слабую ссылку на ячейку для делегата. В вашем Cell
добавьте:
weak var delegate: CellDelegate?
Теперь, настройте ваш контроллер на CellDelegate
протокол. В вашем классе контроллера добавьте:
extension ViewController: CellDelegate {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
}
}
, а пока мы оставим его пустым и завершим его позже.
Теперь контроллер может быть делегатом ячейки. Давайте сделаем это, чтобы быть одним! Обновите метод cellForRowAt
вашего контроллера следующим образом:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? Cell else {
return UITableViewCell()
}
let model = elements[indexPath.row]
cell.update(with: model)
cell.delegate = self
return cell
}
Готово, мы настроили наш контроллер как делегат ячейки! Давайте использовать это как-то!
Создание модели обновления контроллера, когда ячейка сообщает об изменении ее состояния
В вашей ячейке подключите IBActions для каждой кнопки отдельно:
@IBAction func onFirstButtonTapped(_ sender: RoundButton) {
}
@IBAction func onSecondButtonTapped(_ sender: RoundButton) {
}
@IBAction func onThirdButtonTapped(_ sender: RoundButton) {
}
Всякий раз, когданажата кнопка, мы хотим, чтобы наша ячейка сообщала контролеру об изменении состояния, например:
@IBAction func onFirstButtonTapped(_ sender: RoundButton) {
delegate?.onCellModelChange(cell: self, model: .first)
}
Реализуйте два других метода соответствующим образом.
В вашем контроллере давайте вернемся к onCellModelChange
метод. Теперь, когда произошло действие с ячейкой, нам нужно найти элемент в массиве elements
, соответствующий этой ячейке. Чтобы сделать это, мы можем использовать метод tableView
-s -indexPath(for:)
:
extension ViewController: CellDelegate {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
guard let indexPath = tableView.indexPath(for: cell) else {
return
}
print(indexPath)
}
}
Если вы запустите приложение, на этом этапе вы должны увидеть журналы указателей, соответствующие ячейкам, которые вы нажимаетекнопки включены. Не совсем то, что нам нужно.
В нашем табличном представлении представлен только один раздел, поэтому мы можем игнорировать раздел из пути индекса и рассматривать только строку, которая будет такой же, как индекс нашего элемента. Обновим значение в массиве, используя этот индекс:
extension ViewController: CellDelegate {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
guard let indexPath = tableView.indexPath(for: cell) else {
return
}
let index = indexPath.row
elemets[index] = model
}
}
Теперь, если вы запустите это, вы должны обновить модель, но состояние ячейки не будет обновляться сразу. Вы по-прежнему можете видеть, как оно работает, если прокрутить ячейку за пределами экрана и снова прокрутить назад.
Последний бит обновляет ячейку сразу. Как мы можем сделать это? Давайте просто поместим обновленную модель обратно в ячейку:
extension ViewController: CellDelegate {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
guard let indexPath = tableView.indexPath(for: cell) else {
return
}
let index = indexPath.row
elemets[index] = model
cell.update(with: model)
}
}
И это должно быть! Я не проверял и не компилировал :) Так что, если вы найдете какие-либо опечатки, дайте мне знать :) Cheers