A
A
AngelinaShamanova2020-08-03 21:27:07
iOS
AngelinaShamanova, 2020-08-03 21:27:07

How to update Realm in realtime in UICollectionViewCell and display result on screen?

Good evening!
Please help me to solve the problem with updating Realm data and displaying it on the screen.
I have a custom cell in a UICollectionViewController that takes data from the Realm and displays it.
This cell has a button, by clicking on which I should decrease the number in the Realm. Changes should immediately fall into the Realm and be displayed on the screen.
Everything works exactly until I start scrolling the UICollectionView and try to change the next value (for example, the value of the second object). Then just some kind of confusion begins and the number changes not in the cell where I press the button, but in the previous one.
I can assume that this happens because the cells are reused, but I don’t understand how to solve this :(

Another question on the same topic: is it possible to somehow replace reloadData() in collectionViewController with callbacks from dataSource and delegate? If so, how? I watched a video about callbacks, but I don’t understand how to use them to update data.

I hope for your help!

Cell code:

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 code:

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)
}
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
Ivan Vorobei, 2020-08-03
@ivanvorobei

Hello Angelina!
I'll start with the essential , a huge amount of code and text is not conducive to answering your question. I strongly advise in the future to localize the problem, and to frame each problem as one question.
Let's move on to the problem.

I have a custom cell in UICollectionViewController

Cell which controller is a collection? You probably copied the class name incorrectly. Further I will say that your cell is UICollectionViewCell .
I didn’t see the link of the target to the button in the cell, but I’m sure it is somewhere. The reuse system will break your work with targets . Remove them in the preparation method and reconfigure.
You are reloading the collection in the viewWillAppear method, you do n't have to do this .
is it possible to somehow replace reloadData() in collectionViewController with callbacks from dataSource and delegate

A very strange question, horses, people... Reformat, I'll try to answer.
But in general , reloadData is a forced reload . Perhaps you want animated changes, then take a look at my SPDiffable library and tutorial on it. Also a cool tool - realm data observer , works out of the box.
If you want to update the data in a cell , you need to use the cellForRow method , and expand the cell with the desired class.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question