DanCode
DanCode

Reputation: 673

Properties in Realm results are nil

I don't understand why I am failing to print out the properties of my realm result. when I print existingCart[i].${property}, it always give me a default value for all iteration i.

the statement print(existingCart) has no problem. It contains non default values in the properties. It returns:

    Results<Product> <0x7fe5d8f3a770> (
    [0] Product {
        itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 232200 total bytes>;
        itemName = Ground Beef;
        price = 6.53;
        unit = 450 g;
        quantity = 1;
        isInCart = 0;
    },
    [1] Product {
        itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe1004c — 153015 total bytes>;
        itemName = Chicken Drumsticks;
        price = 9.06;
        unit = 1.25 kg;
        quantity = 1;
        isInCart = 0;
    },
    [2] Product {
        itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 242980 total bytes>;
        itemName = Ground Turkey;
        price = 6.91;
        unit = 450 g;
        quantity = 2;
        isInCart = 0;
    },
    [3] Product {
        itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 224128 total bytes>;
        itemName = Canned Beans;
        price = 1.79;
        unit = 398 mL;
        quantity = 1;
        isInCart = 0;
    },
    [4] Product {
        itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe10058 — 252231 total bytes>;
        itemName = Frosted Flakes;
        price = 9.49;
        unit = 1.06 kg;
        quantity = 1;
        isInCart = 0;
    },
    [5] Product {
        itemImage = <ffd8ffe0 00104a46 49460001 01000048 00480000 ffe1004c — 165948 total bytes>;
        itemName = Gouda Cheese;
        price = 4.99;
        unit = 300 g;
        quantity = 1;
        isInCart = 0;
    }
)

This is how I try to load the data from Realm:

private func loadExistingCart() {
    let realm = try! Realm()

    let existingCart = realm.objects(Product.self)
    print(existingCart) // see above
    for i in 0..<existingCart.count {
        print(existingCart[i].itemName) // empty string
        print(existingCart[i].price) // 0.0
        print(existingCart[i].quantity) // 0
        print(existingCart[i].unit) // empty string
        cart.addItem(existingCart[i]) // adds
    }
}

Here is the product class:

import UIKit
import Foundation
import Realm
import RealmSwift

class Product : Object {

    // MARK: Properties
    @objc var itemImage = Data()
    @objc var itemName: String = ""
    @objc var price: Float = 0.0
    @objc var unit: String = ""
    @objc var quantity: Int = 0
    @objc var isInCart: Bool = false

    convenience init?(itemImage: UIImage?, itemName: String, price: Float, unit: String, quantity: Int, isInCart: Bool = false) {
        self.init()
        // itemName, unit, category should not be empty
        guard (!itemName.isEmpty && !unit.isEmpty) else {
            return nil
        }

        // price should not be a negative number
        guard (price >= 0) else {
            return nil
        }

        // Initialize stored properties
        self.itemImage = UIImageJPEGRepresentation(itemImage!, 0.9)!
        self.itemName = itemName
        self.price = price
        self.unit = unit
        self.quantity = quantity
        self.isInCart = isInCart
    }

    override class func primaryKey() -> String? {
        return "itemName"
    }

}

This is how products are being saved

private func saveToCart(product: Product, update: Bool) {
    let realm = try! Realm()
    print(product)
    try! realm.write {
        realm.add(product, update: true)
    }
}

Upvotes: 2

Views: 801

Answers (2)

Chris Shaw
Chris Shaw

Reputation: 1610

You've made a tiny error in the declaration of the Product class there, and it's just a common gotcha with using Realm.

If you look back over all the Realm examples in their documentation, you'll see that each member field should be declared such as this corrected one:

@objc dynamic var itemImage = Data()

Yep, you've missed out the dynamic modifier on each of your properties. Go back and add that to each property and it should just start working. For completeness, this should be the properties declaration:_

// MARK: Properties
@objc dynamic var itemImage = Data()
@objc dynamic var itemName: String = ""
@objc dynamic var price: Float = 0.0
@objc dynamic var unit: String = ""
@objc dynamic var quantity: Int = 0
@objc dynamic var isInCart: Bool = false

You can google the dynamic keyword for an explanation. It's based on the fact that the object you have is just a proxy to a database object, and Realm needs to intercept the property access to actually interrogate the database and retrieve the value of the property. You can see the same effect as your problem if you ever try to look at an object in the debugger - it's just full of the default values.

Upvotes: 2

Chris Frederick
Chris Frederick

Reputation: 5584

I'm not familiar enough with how Realm works to say why you can't seem to access the objects by index, but perhaps you could try accessing them as part of a Sequence instead?

let existingCart = realm.objects(Product.self)

for item in existingCart {
    print(item.itemName)
    print(item.price)
    print(item.quantity)
    print(item.unit)
}

Upvotes: 0

Related Questions