luky
luky

Reputation: 2370

Is it possible to make copy of Realm object?

I want to refresh the Realm database in the background thread like this: (Because I have got fresh data from Webservice)

 RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
[realm deleteAllObjects]; // !!
[Pubs createOrUpdateInRealm:[RLMRealm defaultRealm] withJSONArray:data];
[realm commitWriteTransaction];

Problem is, that meanwhile I delete & renew the objects in Realm db, user can open some Detail ViewController pointing to some Realm object (Pubs) which has been deleted meanwhile so the exception is thrown.

I don't see any solution for this, except always when I would like to access the Realm object from Detail controller or its property I would need to always do something like this:

(That means always get Realm object, but that can probably fail too)

pub = [Pubs objectsWhere:[NSString stringWithFormat: @"pubId = %lu", (long)_selectedPubId]].firstObject;

But I am not using this solution. I am thinking best would be if I could call in Detail view controller something like this:

pub = [Pubs objectsWhere:[NSString stringWithFormat: @"pubId = %lu", (long)_selectedPubId]].firstObject;
pub = [pub safeCopy];

So the PubRealmObject can be meanwhile deleted, but the pub object will solo exist in the memory (only for the purpose to access its data properties).

So did someone try something similar?

Or maybe even using some iOS SDK way like this?

I need to only access the data properties as I say, not operate with realm object methods like delete or update the object in the db.

Btw I tried to call the update of Realm db in the main thread, but the problem is it takes like 5-7 seconds (only 1000 JSON objects) so it lags the application. That's why I am thinking the background update & safe copying of object could be better.

But I am thinking that it can fail even while copying the object, so what is the solution for this? (background update vs safe access of Realm object)

Upvotes: 4

Views: 5657

Answers (2)

ImShrey
ImShrey

Reputation: 418

With Swift:

Previously answered here

As of now, Dec 2020, there is not proper solution of this issue. We have many workarounds though.

Here is the one I have been using, and one with less limitations in my opinion.

  1. Make your Realm Model Object classes conform to codable
class Dog: Object, Codable{
    @objc dynamic var breed:String = "JustAnyDog"
}
  1. Create this helper class
class RealmHelper {
    //Used to expose generic 
    static func DetachedCopy<T:Codable>(of object:T) -> T?{
       do{
           let json = try JSONEncoder().encode(object)
           return try JSONDecoder().decode(T.self, from: json)
       }
       catch let error{
           print(error)
           return nil
       }
    }
}
  1. Call this method whenever you need detached / true deep copy of your Realm Object, like this:
 //Suppose your Realm managed object: let dog:Dog = RealmDBService.shared.getFirstDog()
 guard let detachedDog = RealmHelper.DetachedCopy(of: dog) else{
    print("Could not detach Note")
    return
 }
//Change/mutate object properties as you want
 detachedDog.breed = "rottweiler"

As you can see we are piggy backing on Swift's JSONEncoder and JSONDecoder, using power of Codable, making true deep copy no matter how many nested objects are there under our realm object. Just make sure all your Realm Model Classes conform to Codable.

Though its NOT an ideal solution, but its one of the most effective workaround.

Upvotes: 0

TiM
TiM

Reputation: 15991

It's usually not a good design pattern to have a view controller relying on a data model that can be deleted out from underneath it. It's possible to check if a Realm object has been deleted to avoid exceptions by checking its object.invalidated property.

In any case, to create a detached copy of a Realm object, all you need to do is:

RLMObject *copiedObject = [[RLMObject alloc] initWithValue:object];

This will make a copy of the object, but it will not be inserted into any Realm instance. Please note that if the object links to any other Realm objects, these will not be copied as well; the new object will just be pointing at the existing copies.

But I still feel like I need to mention that you could probably just make your implementation of updating Realm from your web service a bit smarter to avoid the need to do this.

If your objects implement a primary key, then when you call createOrUpdateInRealm, the existing objects will be updated with the new values.

Good luck!

Upvotes: 12

Related Questions