2
votes

I have a model which is a swift object.

I retrieve data from the web and then I need to update my object but there are different cases to handle:

  1. I create an object, fetch the data, update the properties, save it in realm
  2. I create an object, save it in realm, fetch the data, update the properties, save it again
  3. I create an object, save it in realm, start to fetch the data, delete it from realm, receive the data, do nothing.

And this is how I handle it:

  1. If self.invalidated == false & self.realm == nil -> update the properties on self

  2. If self.invalidated == false & self.realm != nil -> Fetch the object from Realm in a background thread, set the properties, Refresh Realm on main thread before completion

  3. If self.invalidated == true -> Stop (object has been deleted so it's not needed anymore)

One solution to simplify this code is to save the object in realm, but I don't want to save an object that could be dirtier than a potential one in realm. Or I could fetch whatever I have in realm before fetching the data online, so that I'm sure I save something at least as dirty as one in realm (but performance is not as optimal as it could be)

Could you give me some insight about what is the cleanest way to handle such a case?

Here is my code at the moment:

func fetchDataOnline(completion:(success : Bool)->()){

    let params = ["tmdb_id":self.tmdbId,"lang":kLang]

    let tmdbId = self.tmdbId

    let invoker = AWSLambdaInvoker.defaultLambdaInvoker()
    invoker.invokeFunction("getMovie", JSONObject: params).continueWithBlock { (task) -> AnyObject? in

        guard self.invalidated == false else{
            DDLogWarn("Movie has been invalidated while fecthing data")
            completion(success: false)
            return nil
        }

        if let dic = task.result as? NSDictionary{

            var objectToUpdate = self

            if self.realm != nil{ //Use new realm instance
                guard let newRealmInstance = try! Realm().objectForPrimaryKey(MovieNew.self, key: tmdbId) else{
                    DDLogError("self.realm not nil but can't find movie in realm")
                    completion(success: false)
                    return nil
                }

                objectToUpdate = newRealmInstance
            }

            try! Realm().write{
                objectToUpdate.setProperties(dic: dic)
                objectToUpdate.lastUpdate = NSDate()
            }
        }
        else{ //No dictionary found from result
            if let error = task.error{
                DDLogError(error.description)
            }
            DDLogError("Error getting movie")
        }

        Async.main{
            try! Realm().refresh()
            completion(success : task.error == nil)
        }

        return nil
    }
}
1

1 Answers

1
votes

Given your specific use-case scenarios, I think this looks like the best way to go about doing it. While you could do state tracking within the Realm objects themselves, it's much better to simply track their status against their parent Realm objects and respond to that accordingly.

The main best practice for Realm is mainly to try and minimize the number of write transactions as much as possible., so the only thing I could potentially question here is if it's absolutely necessary to add an object to a Realm before performing the request, only to potentially delete it again before the download is complete. If that's necessary because you're using those objects as placeholders in your UI, then that's perfectly fine.

Either way, all of this is really a matter of opinion. This solution you've put forward is competent and fills all of your requirements, so I'm not sure if it's worth trying to find something better. :)