как сохранить состояние кнопки отдельной ячейки tableView в UserDefaults
Нужно, чтобы при нажатии на кнопку в ячейке кнопка изменила свое изображение, а при повторном запуске приложения изображение этой кнопки оставалось измененным. У меня при изменении кнопки в одной ячейке, при перезапуске приложения изменяются изображения кнопок всех ячеек таблицы.
вот код cellForRowAt :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CoverCell", for: indexPath) as! CoverTableViewCell
let cover = presenter.covers?[indexPath.row]
cell.coverNameLabel?.text = cover?.title
guard let url = URL(string: presenter.covers?[indexPath.row].image ?? "") else { return cell }
cell.coverImageView.sd_setImage(with: url, completed: nil)
let favoriteButton = UIButton(frame: .init(x: 0, y: 0, width: 35, height: 35))
favoriteButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
favoriteButton.tag = indexPath.row
favoriteButton.setImage(UIImage(named: "star"), for: .normal)
favoriteButton.setImage(UIImage(named: "blackStar"), for: .selected)
favoriteButton.isSelected = UserDefaults.standard.bool(forKey: "isSaved")
UserDefaults.standard.synchronize()
cell.accessoryView = favoriteButton
return cell
}
а вот функция нажатой кнопки:
@objc func buttonTapped(sender: UIButton) {
sender.isSelected = !sender.isSelected
UserDefaults.standard.set(sender.isSelected, forKey: "isSaved")
UserDefaults.standard.synchronize()
if sender.isSelected {
guard let covers = presenter.covers else { return }
FavoriteCovers.favoriteCovers.append(covers[sender.tag] )
}
}
Буду признателен за помощь, думал что возможно нужно сделать массив кнопок, но не смог реализовать это. Занимаюсь всего пару месяцев, спасибо
Ответы (1 шт):
Вариант 1
Если набор данных остается неизменным и в таблицу не добавляются новые записи, то проще всего сохранять массив выбранных индексов
class FavoriteCovers {
// ...
static var coverIdentifiers: [Int]!
}
Читаем при загрузке приложения
FavoriteCovers.coverIdentifiers = UserDefaults.standard.array(forKey: "coverIdentifiers") as? [Int] ?? []
tableView.reloadData()
В методе func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell восстанавливаем выбор
favoriteButton.isSelected = FavoriteCovers.coverIdentifiers.contains(indexPath.row)
Сохраняем выбранные кнопки
@objc func buttonTapped(sender: UIButton) {
sender.isSelected.toggle()
guard let covers = presenter.covers else {
return
}
if sender.isSelected {
FavoriteCovers.favoriteCovers.append(covers[sender.tag])
FavoriteCovers.coverIdentifiers.append(sender.tag)
} else {
// сравниваем заголовки, также можно добавить другие условия для идентификации
FavoriteCovers.favoriteCovers.removeAll { $0.title == covers[sender.tag].title }
FavoriteCovers.coverIdentifiers.removeAll { $0 == sender.tag }
}
UserDefaults.standard.set(FavoriteCovers.coverIndices, forKey: "coverIdentifiers")
}
Вариант 2
Если скажем при загрузке приложения список может измениться (удалили или добавили записи во внешнем источнике, откуда они грузятся), то индексы для сохранения использовать не получится, так как они сместятся. В этом случае нужен какой-то другой уникальный идентификатор для записей, например сочетание title + image. Тогда можно сделать так
struct Cover {
var title: String?
var image: String?
var identifier: String {
(title?.data(using: .utf8)?.base64EncodedString() ?? "") + (image?.data(using: .utf8)?.base64EncodedString() ?? "")
}
}
//...
FavoriteCovers.coverIdentifiers = UserDefaults.standard.stringArray(forKey: "coverIdentifiers") ?? []
//...
favoriteButton.isSelected = FavoriteCovers.coverIdentifiers.contains(presenter.covers?[indexPath.row].identifier ?? "")
//...
if sender.isSelected {
FavoriteCovers.favoriteCovers.append(cover)
FavoriteCovers.coverIdentifiers.append(cover.identifier)
} else {
// сравниваем заголовки, также можно добавить другие условия для идентификации
FavoriteCovers.favoriteCovers.removeAll { $0.title == cover.title }
FavoriteCovers.coverIdentifiers.removeAll { $0 == cover.identifier }
}