Converting local realm to synced realm in the middle of app life cycle (in Swift)


#1

My app will have a paid feature called multi-devices sync. I would like to implement the feature with Realm Platform - Query Based Sync.

I know how to convert local realm to synced realm thanks to this thread.

But it’s based on the scenario that users sync their realm from the app start - before opening their non-synced local realm. That doesn’t work for me because my users will start sync when they paid for it.

Therefore, I have to convert their local realm in the middle of app life cycle and the local realm is already opened by that time.

My issue starts here. When I try to convert local realm to synced realm, app crashes with this message “Realm at path ‘…’ already opened with different read permissions”.

I tried to find a way to close local realm before converting it, but Realm cocoa does not allow me to close a realm programmatically.

Here’s my code converting local realm to synced realm.

func copyLocalRealmToSyncedRealm(user: RLMSyncUser) {
        
        let localConfig = RLMRealmConfiguration()
        localConfig.fileURL = Realm.Configuration.defaultConfiguration.fileURL
        localConfig.dynamic = true
        localConfig.readOnly = true
        
        // crashes here
        let localRealm = try! RLMRealm(configuration: localConfig)

        let syncConfig = RLMRealmConfiguration()
        syncConfig.syncConfiguration = RLMSyncConfiguration(user: user,
                                                            realmURL: realmURL,
                                                            isPartial: true,
                                                            urlPrefix: nil,
                                                            stopPolicy: .liveIndefinitely,
                                                            enableSSLValidation: true,
                                                            certificatePath: nil)
        syncConfig.customSchema = localRealm.schema
        
        let syncRealm = try! RLMRealm(configuration: syncConfig)
        syncRealm.schema = syncConfig.customSchema!
        try! syncRealm.transaction {
            let objectSchema = syncConfig.customSchema!.objectSchema
            for schema in objectSchema {
                let allObjects = localRealm.allObjects(schema.className)
                for i in 0..<allObjects.count {
                    let object = allObjects[i]
                    RLMCreateObjectInRealmWithValue(syncRealm, schema.className, object, true)
                }
            }
        }
    }

Any help will be appreciated.
Thanks.


#2

I posted this a week ago and it seems that nobody knows any solution for this.
This is a common use case though realm cloud is not ready for this?
Maybe there are fewer apps built with realm cloud than I thought and perhaps I’m the first one who try to sync the realm for the paid users only.


#3

It’s frustrating when you are trying to do a simple thing and you can’t get a response. You can always open a support ticket but before doing that, a few things to look at.

First, and not to rehash old topics but read Does anyone user Realm Cloud for production. The last note by @roberhofer is very important.

Second thing is the Github article you are following is two years old and is not current. The code isn’t correct. Realm has changed and updated just about all aspects of syncing in the last couple of years. We spent literally months trying to get a query based sync to work and never could - mostly due to incorrect and outdated documentation.

It’s better now so take a look at the current docs Using Sync’d Realms

Here’s a question; if you’re currently using a local realm, why are you doing this

let localRealm = try! RLMRealm(configuration: localConfig)

Can’t you just do this to get the default local realm?

// Get the default Realm
let realm = try! Realm()

Also… If you want to open a query based realm the code is something like this (from the current docs)

// Create the configuration
let syncServerURL = URL(string: "realms://myinstance.cloud.realm.io/~/userRealm")!
let config = user.configuration(realmURL: syncServerURL)

// Open the remote Realm
let realm = try! Realm(configuration: config)
// Any changes made to this Realm will be synced across all devices!

Lastly, I believe you need to be using SyncUser.configuration() for accessing the sync’d realm. Here’s a link to the SyncUser API


#4

Thank you for your reply.

The reason why I am trying to open a new local realm of type RLMRealm is Realm() and RLMRealm() has different properties.

If I use a default Realm which is already opened, I can’t access allObjects properties thus I can’t copy local realm to synced realm.

let allObjects = localRealm.allObjects(schema.className)

Also, Realm and RLMRealm both have schema property but they are different type so I can’t assign Realm.schema to RLMRealm.schema.

syncConfig.customSchema = localRealm.schema

I wish to know if there is a way to copy local realm to synced realm without creating a new RLMRealm().

PS. Here’s another one who suffered from the same issue. And it’s not clear that he somehow solved the issue. It seems that there’s no official solution for this issue.