thetipsyhacker
thetipsyhacker

Reputation: 1412

UITableView Performance with Realm Objects in cellForRowAt indexPath

I have many different sections of categories in my tableView loaded from a variable called allProducts which holds all my Realm objects (of type Results<Product>).

The correct products are being loaded in each section, however, ever since I introduced this piece of code:

switch productViewSegmentedControl!.selectedSegmentIndex {

    case 0:
        allProductsInSection = allProducts.filter("itemgroup = %@", allProductSections[indexPath.section])
    case 1:
        allProductsInSection = allProducts.filter("itembrand = %@", allProductSections[indexPath.section])
    case 2:
        allProductsInSection = allProducts.filter("itemtype = %@", allProductSections[indexPath.section])
    default:
        allProductsInSection = allProducts.filter("itemgroup = %@", allProductSections[indexPath.section])
    }

into my cellForRowAt indexPath method, the UI lags when scrolling at sections of the tableView where there are many items.

Each cell in the tableView holds let product = allProductsInSection![indexPath.row]. The product constant holds the properties for each item from my Product model class.

What can I do to increase performance of the UI?

P.S. each cell is already being reused:

let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell") as? OrderFormViewCell
            ?? UITableViewCell(style: .subtitle, reuseIdentifier: "ProductCell") as! OrderFormViewCell

Upvotes: 3

Views: 469

Answers (2)

bdash
bdash

Reputation: 18308

Having the switch statement you describe in your tableView(_:cellForRowAt:) method means that you're forcing Realm to re-filter the products every time a cell is about to be displayed. From the code you've shared it looks like you have a segmented control that controls which products to display. Instead of checking the segmented control's selection when preparing each cell, you should instead react to its selection changing and filter your products into an instance variable which tableView(_:cellForRowAt:) can use. This will allow Realm to filter the products only when the criteria has changed rather than every time a cell is about to be displayed.

Since you need to filter using a different value within each section of your table view, you'll want to prepare one Results for each section of the table view. In a method that you call when the segmented control's selection changes:

var productsPerSection = []
for section in 0..numberOfSections {
    let productsInSection: Results<Product>
    switch productViewSegmentedControl!.selectedSegmentIndex {
        case 0:
            productsInSection = allProducts.filter("itemgroup = %@", allProductSections[section])
        case 1:
            productsInSection = allProducts.filter("itembrand = %@", allProductSections[section])
        case 2:
            productsInSection = allProducts.filter("itemtype = %@", allProductSections[section])
        default:
            productsInSection = allProducts.filter("itemgroup = %@", allProductSections[section])
    }
    productsPerSection.append(productsInSection)
}

self.productsPerSection = productsPerSection

Then in your tableView(_:cellForRowAt:) method, use self.productsInSection[indexPath.section] instead of filtering to create allProductsInSection.

Note: the code is an untested sketch that should hopefully communicate the general idea about the approach, but likely doesn't compile.

Upvotes: 1

Khalid Afridi
Khalid Afridi

Reputation: 923

You have to check that you are dequeuing your cells properly. also if you have images in cells it will be good to clean dequeued cells there is a func called prepare for reuse clean your cells properly

Upvotes: 0

Related Questions