@AngelinaShamanova

Как обновить Realm в реальном времени в UICollectionViewCell и отобразить результат на экране?

Добрый вечер!
Помогите, пожалуйста, решить проблему с обновлением данных Realm и отображением их на экране.
У меня есть кастомная ячейка в UICollectionViewController, которая принимает данные из Realm и отображает их.
На этой ячейке есть кнопка, по нажатию на которую у меня должно уменьшаться число, находящееся в Realm. Изменения сразу должны попадать в Realm и отображаться на экране.
Все работает ровно до того момента, пока я не начинаю скроллить UICollectionView и не пытаюсь изменить следующее значение (например, значение второго объекта). Тогда начинается просто какая-то путаница и число меняется не в той ячейке, где я нажимаю кнопку, а в предыдущей.
Могу предположить, что так случается, потому что ячейки переиспользуются, но как решить это - не понимаю :(

Еще один вопрос в эту же тему: возможно ли как-то заменить reloadData() в collectionViewController на коллбэки от dataSource и delegate? Если да, то как? Посмотрела видео про коллбэки, но не понимаю как их использовать для обновления данных.

Надеюсь на вашу помощь!

Код ячейки:

import UIKit
import RealmSwift

class StorefrontCell: UICollectionViewCell {

var product: Results<Product>!
let data = DataLoader().productInformation

@IBOutlet var name: UILabel!
@IBOutlet var price: UILabel!
@IBOutlet var quantity: UILabel!
@IBOutlet var buy: UIButton!

func configure(with productList: Product) {
    
    buy.layer.cornerRadius = 10
    buy.isHidden = false 
    name.text = "Наименование товара: \(productList.name)"
    price.text = "Цена: \(productList.price)"
    quantity.text = "Количество: \(productList.quantity)"
}

func configureNotAvailableProduct(with productList: Product) {
    buy.isHidden = true
    name.text = "Наименование товара: \(productList.name)"
    price.text = "Цена: \(productList.price)"
    quantity.text = "ТОВАРА НЕТ В НАЛИЧИИ"
}

@IBAction func buyAction(_ sender: UIButton) {
    
    product = realm.objects(Product.self)
    
    for result in product {
        
        let newQt = result.quantity - 1
        quantity.text = "Количество: \(newQt)"
        
        try! realm.write {
            result.quantity = newQt
        }
        if result.quantity == 0 {
            self.buy.isHidden = true
            self.quantity.text = "ТОВАРА НЕТ В НАЛИЧИИ"
        } else { return }
    }
}
}


Код CollectionView:

import UIKit
import RealmSwift

class StoreFrontViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

var product: Results<Product>!

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    collectionView.reloadData()
}

override func viewDidLoad() {
    super.viewDidLoad()
    product = realm.objects(Product.self)
    self.collectionView.register(UINib(nibName: "StorefrontCell", bundle: nil), forCellWithReuseIdentifier: "StorefrontCell")
}

// MARK: UICollectionViewDataSource

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return product.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StorefrontCell", for: indexPath) as! StorefrontCell
    
    
    let productInfo = product[indexPath.item]
    
    if productInfo.quantity != 0 {
        cell.configure(with: productInfo)
    } else {
        cell.configureNotAvailableProduct(with: productInfo)
    }
    
    return cell
}

// MARK: UICollectionViewDelegate

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: UIScreen.main.bounds.width - 10, height: UIScreen.main.bounds.width)
}
}
  • Вопрос задан
  • 101 просмотр
Пригласить эксперта
Ответы на вопрос 1
IvanVorobei
@IvanVorobei
iOS разработчик, канал https://t.me/sparrowcode
Ангелина, здравствуйте!

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

Перейдем к проблеме.

У меня есть кастомная ячейка в UICollectionViewController


Ячейка, которая контроллер-коллекция? Наверное, вы неправильно скопировали название класса. Дальше буду говорить будто ваша ячейка UICollectionViewCell.

Не увидел в ячейке привязку таргета к кнопке, но уверен она где то есть. Система переиспользования сломает вам работу с таргетами. Убирайте их в методе подготовки и конфигурируете заново.

Вы перезагружаете коллекцию в методе viewWillAppear, так делать не нужно.

возможно ли как-то заменить reloadData() в collectionViewController на коллбэки от dataSource и delegate

Очень странный вопрос, кони, люди... Переформатируйте, постараюсь ответить.
Но вообще reloadData это форсированная перезагрузка, Возможно вы хотите анимированные изменения, тогда посмотрите на мою библиотеку SPDiffable и туториал по ней. Так же крутой инструмент - обсервер данных риалма, работает из коробки.

Если же вы хотите обновлять данные в ячейке, вам нужно воспользоваться методом cellForRow, и развернуть ячейку с нужным классом.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы