1
votes

I load a list of objects from my server and save them to Realm using ObjectMapper. Each object contains an url defining where to load the image for the object. I load the image and save the imagedata in the realm object so that I don't need to reload it every time. But unfortunately the image data is lost if I reload the data.

I use a primary key and my thought was that when the JSON. I fear that ObjectMapper doesn't update existing objects in Realm but overwrites them. So the imagedata is nil and must be refetched from server. Is there something I can do do prevent this?

Here is my simplified ObjectMapping-File:

import Foundation
import ObjectMapper
import RealmSwift

class OverviewItem: PersistentObject {

    override var hashValue : Int {
        get {
            return self.overviewID.hashValue
        }
    }

    dynamic var overviewID: Int = 0
    dynamic var titleDe: String = ""
    dynamic var imageUrl: String = ""
    dynamic var imageData: NSData?

    required convenience init?(_ map: Map) {
        self.init()
    }

    //computed properties
    dynamic var image: UIImage? {
        get {
            return  self.imageData == nil ? nil : UIImage(data: self.imageData!)
        }
        set(newImage){
            if let newImage = newImage, data = UIImagePNGRepresentation(newImage){
                self.imageData = data
            }
            else{
                self.imageData = nil
            }
        }
    }

    //image is a computed property and should be ignored by realm
    override class func ignoredProperties() -> [String] {
        return ["image"]
    }

    override func mapping(map: Map) {
        overviewID <- map["infoid"]
        titleDe <- map["titleDe"]
        imageUrl <- map["imageurl"]
    }

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

And here how I fetch the image and update the object:

 func fetchImage(item: OverviewItem, successHandler: UIImage? ->(), errorHandler: (ErrorType?) -> ()){

        AlamofireManager.Configured
            .request(.GET, item.imageUrl)
            .responseData({ (response: Response<NSData, NSError>) in

                if let error = response.result.error{
                    logger.error("Error: \(error.localizedDescription)")
                    errorHandler(error)
                    return
                }

                if let imageData = response.result.value{

                    successHandler(UIImage(data: imageData))

                    let overviewID = item.overviewID  
                    let queue = NSOperationQueue()
                    let blockOperation = NSBlockOperation {

                        let writeRealm = try! Realm()
                        do{
                            if let itemForUpdate = writeRealm.objects(OverviewItem).filter("overviewID = \(overviewID)").first{
                                try writeRealm.write{
                                    itemForUpdate.imageData = imageData
                                    writeRealm.add(itemForUpdate, update: true)
                                }
                            }
                        }
                        catch let err as NSError {
                            logger.error("Error with realm: " + err.localizedDescription)
                        }  
                    }
                    queue.addOperation(blockOperation)
                }
            })
    }
1
Can you share some code (where you create the object and save it to realm) - bcamur

1 Answers

1
votes

You would need to pull the existing image data by primary key before you add / upsert your object to the Realm. You could do that e.g. in a method, which abstracts ObjectMapper's mapping, but still allows providing a Realm instance.

But in general, I wouldn't recommend to store images in the Realm itself for that purpose. There are some really good image caching frameworks out there, which allow you to cache images on disk and in memory. These allow you in addition to organize the cache by size, they assist you with fast decompression and they allow you to manage expiry times.