Realm async vers Realm local?

Bonjour à tous,

Cela fait quelques jours que je cherche… et aucune solution trouvée.

J’ai créé une application qui utilise une base Realm en local, mais qui est capable aussi de stocker des informations partagées sur une base Realm Cloud.
En gros, j’ai 2 boutons: l’un stocke sur le device, l’autre sur le Realm Cloud avec une instance attachée à mon application.
Si j’appuie sur le bouton 1 (local), ma base locale s’ouvre et je stocke en local. Si j’appuie ensuite sur le bouton 2 (cloud), ma base partagée s’ouvre après authentification et je peux stocker également sur cette base. Cela fonctionne très bien…

Le problème est qu’ensuite je ne peux plus « retrouver » ma base locale. Je ne peux plus « stocker » sur mon device de nouveau…

J’ai essayé SyncUser.current?.logOut(), je voudrais « déconnecter » cette base pour que je puisse de nouveau stocker en local, mais je ne trouve pas…
Je suppose qu’il faudrait initialiser 2 configurations différentes: Realm(configuration: localConfig) et une seconde Realm(configuration: cloudConfig) par exemple que j’appellerai séparément.
J’ai consulté la doc realm mais je ne trouve pas comment restaurer la configuration par défaut (local)

Cela est-il possible?

Si quelqu’un peut m’aider, il est le bienvenu…
Merci à vous,

Joel

Si je ne me trompe pas, les bases locales des Realm Cloud ne sont pas les mêmes que les bases locales que l’on utiliserait so on travaille en local.

As-tu essayé en spécifiant un chemin de fichier local ?

Sinon pq ne pas laisser Realm gérer le local et le cloud ? Il le fait très bien

Merci pour la réponse rapide…
J’ai essayé de renseigner le chemin de ma base locale (url locale), mais je ne sais pas comment le coder en swift. Toutes mes tentatives ont échoué ! Exemple: localConfig.fileURL = Realm.Configuration.defaultConfiguration.fileURL n’aboutit à rien…
Peut-on « forcer » Realm à écrire sur un fichier spécifique qui serait plus facile à retrouver ensuite?
Si vous avez une solution pour moi…

C’est pourtant un élément de la V4.4.0

Tu peux voir via ce lien ce qu’il faut faire.

Merci. Je viens cependant de consulter ces documents et j’ai vraiment des difficultés à comprendre la démarche à effectuer.
Pourquoi est-il si facile de passer de local Realm à Realm Cloud et pourquoi est-ce si compliqué de faire l’inverse?
Je continue de lire et d’essayer de comprendre mais mes compétences sont déjà sollicitées à plein régime…
Merci encore…

Mais juste un truc.

Je ne comprends pas pq tu veux gérer le local et le cloud alors que si ton app gère le cloud, Realm gère le local automatiquement.

C’est une application sur laquelle par défaut l’utilisateur (lambda…) doit pouvoir déposer un carnet de suivi de séances d’entrainements dans une base locale.
Cette application a été conçue également pour que chaque utilisateur (étudiants) puisse pour certaines séances accéder à une base cloud (user + code d’accès perso) créée par un enseignant (qui lui seul détient le code administrateur lui permettant d’avoir accès aux séances de ses étudiants pour correction)…
Cela fonctionne très bien dans un seul sens:
-> L’utilisateur saisis en local sur son device (Realm le gère effectivement tout seul). Il se connecte ensuite à la base de données créée par son enseignant pour saisir certaines séances avec son mot de passe (instance Realm avec un « chemin » spécifique vers la base Realm Cloud.
-> S’il désire de nouveau saisir en local, Realm reste « bloqué » sur la base cloud et toutes saisies ultérieures s’effectuent sur l’instance Realm Cloud !!! Impossible de retrouver le chemin de la base locale… Tout au moins, impossible pour moi jusqu’à présent !
Merci pour vos réponses, je ne désespère pas de comprendre et trouver…

Tu as ton code pour l’accès aux deux bases ?

Lors de l’ouverture de l’application, Realm n’initialise ainsi:
var config = Realm.Configuration.defaultConfiguration
config.deleteRealmIfMigrationNeeded = true
_realm = try! Realm(configuration: config)

La base locale fonctionne très bien. Realm le gère simplement…

Lorsque l’utilisateur veut se connecter à la base Cloud, un viewController d’accueil le dirige vers loginAccount() après lui avoir demandé son nom d’utilisateur (nickname) puis un mot de passe (mdp)

func loginAccount() { // Structure du code épuré :

    let authURL = URL(string: "https://myInstance.cloud.realm.io")!
    let usernameCredentials = SyncCredentials.usernamePassword(username: nickname, password: mdp, register: false)// **renvoie error si le compte n'existe pas**
    
    SyncUser.logIn(with: usernameCredentials, server: authURL, onCompletion: { [weak self](user, err) in
        
        **// Si le compte existe : vers base créée par l’enseignant **
        if let user = user {
            
            let realmUrl = URL(string: "realms://myInstance.cloud.realm.io/~/xxxxx")!
            let syncConfig = SyncConfiguration(user: user, realmURL: realmUrl)
            let realmConfig = Realm.Configuration( syncConfiguration: syncConfig)
            Realm.Configuration.defaultConfiguration = realmConfig

           **// (exemple) Accéder à un viewController « menu des séances à enregistrer »**

        }
            
            **// Si compte n'existe pas:**
        else{
            **print("DESOLE! Erreur compte...")**
                        }
        }
    )
    
}

La configuration par défaut devient donc syncConfig...
La base Cloud fonctionne très bien également. Les objets sont correctement gérés (ajoutés, Supprimés etc...)

Lorsque l’utilisateur veut revenir à la base locale non « associée » à l’URL de l’instance Realm Cloud, je voudrais que Realm se réinitialise dans sa configuration initiale par défaut (qui gérait très bien le local à la 1ère initialisation)

J’avais essayé de récupérer le chemin de la base locale par:
var localConfig = Realm.Configuration()
localConfig.fileURL = Realm.Configuration.defaultConfiguration.fileURL
Mais je n’arrive pas à réutiliser cette adresse... Error file not found  !

Merci pour vos conseils...

Et si tu initialisais Realm uniquement au besoin via des fonctions qui te retournent un Realm ?

De plus utilises-tu des objects identiques ? Perso je créerais des objects « Private » en local et « Shared » sur Realm Cloud.

Et en fonction de ce que l’élève fait, cela s’enregistrerait où il faut.

func syncRealm() -> Realm {
        var syncRealmConfiguration = SyncUser.current!.configuration(realmURL: URL, fullSynchronization: true, enableSSLValidation: true, urlPrefix: nil)
        
        syncRealmConfiguration.objectTypes = [PrivateActivities.self]
        
        let syncRealm = try! Realm(configuration: syncRealmConfiguration)
        return syncGlobalRealm            
}

      func localRealm() -> Realm {
                let  localConfiguration = Realm.Configuration()
                localConfiguration.objectTypes = [SharedActivities.self]
            
            let localRealm = try! Realm(configuration: localConfiguration)
            return localRealm           
    }

Du coup quand tu as besoin de l’un ou de l’autre, tu appelles.

exemple :

    func allPrivateActivities() -> Results<PrivateActivities> {
    let realm = localRealm()
    let privateActivities = realm.objects(PrivateActivities.self)
    return privateActivities
}

Ensuite pour celles de Realm Cloud

func allSharedActivities() -> Results<SharedActivities> {
        let realm = syncRealm()
        let sharedActivities = realm.objects(SharedActivities.self)
        return sharedActivities
    }

Perso je fonctionne comme ça sur l’app que je suis occupé de monter. Alors moi tout est en ligne mais j’ai différents Realms (Global et Private)

J’avais chopé l’idée sur un article de Realm sur l’app Santa Claus.

1 J'aime

Bonjour Krysbe,

Merci pour la proposition… Il m’a fallu quelques jours pour comprendre et essayer de mettre en place dans mon application. Je n’y suis pas arrivé mais par contre j’ai retenu le principe de la double initialisation de realm(local) et realm(cloud) que l’utilisateur appelait le moment venu. Il me fallait créer cependant un chemin de base locale spécifique que je pourrais rappeler précisément.

J’ai enfin réussi ! Cela fonctionne très bien ! Merci beaucoup pour l’idée:

// J’initialise dans un premier temps realm en config locale avec un chemin d’accès:

        let documentUrl = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
        let url = documentUrl.appendingPathComponent("baseLocale.realm")
        
        let configInit = Realm.Configuration(
            fileURL: url,
            inMemoryIdentifier: nil,
            encryptionKey: nil,
            readOnly: false,
            schemaVersion: 1,
            migrationBlock: nil,
            deleteRealmIfMigrationNeeded: true,
            objectTypes: nil)
        
        // Initialiser _realm(Local) en config locale
        _realmLocal = try! Realm(configuration: configInit)

        // Initialiser _realm(cloud) par défaut en base locale
        _realm = try! Realm(configuration: configInit)

// Si l’utilisateur choisit realmCloud, je réinitialise Realm pour accès possible en base Cloud
// Realm => _realm(cloud)

        if "CHOIX CLOUD"{
            
            var config = Realm.Configuration.defaultConfiguration
            config.deleteRealmIfMigrationNeeded = true
            
            Realm.Configuration.defaultConfiguration = config
            
            _realm = try! Realm(configuration: config)
            
        }

… Ce qui me permet de lancer le protocole d’authentification « utilisateur »

L’application « bascule » ainsi d’une base en locale vers une base cloud (et inversement) facilement selon le choix de l’utilisateur…

Super merci…

1 J'aime