Is it reasonable to create ReamManager singleton?


Is it reasonable to create ReamManager singleton which will do any operations with Realm, (for example write to RealmDB) and use it anywhere in the project? Because I tried to do so and I got errors:

Terminating app due to uncaught exception ‘RLMException’, reason: 'Cannot modify managed RLMArray outside of a write transaction.

Or I must import RealmSwift anywhere in project?


Yes. All of my apps, we made some kind of manager that handles the Realm functions (opening, syncing, migration etc.)
Realm is typesafe - its made in a way that you get an error if you try to access it in a different thread. In that case, you will get a RLMException.

The “Cannot modify managed RLMArray outside of a write transaction.” means exactly like what it said - you try to change a Realm object property while you are not in a realm.write transaction.

I have an architect/pattern, that fix both of these errors.
I can write about it more if you want, but its basically a factory-manager pattern with a small change: I map all RealmObjects to structs, so i can pass it freely everywhere :slight_smile:
It’s not perfect but I think its great.


Hello @freeubi . Please write about it more. Thank you.


Hello @freeubi. Can you show examples? Thank you.


Sorry but I can’t right now - at least not without sharing a lot of my apps data and I dont want to do that.
I’m planning to do an open source version of it (just the default things) but I need to allocate time to do that.


First, a few thought:

  • I made it in a way that I should fairy easy change the Realm db to any other. Because of that this is not the simplest architecht.
  • I like to use the Result framework [], so its heavily build on using that, however its not necessery. I wrap a data and an error object with it, and make that as a result.
  • All of the realm operations will go on a dedicated Realm thread.
  • The communication between Factorys <-> Managers <-> UI made with callbacks, because of the thread switch. I am not happy with that.

I have a main RealmManager class with static functions. These functions are connected closely to realm, like user registration, login, logout, creating the realm, migrating, connect to the server etc [its not 100% true, because i have connection handlers too but it doesnt matter it this case].

Most of the apps has a user, so lets take that as an example.
I will have a RealmUser model to store the data and a User struct to use it on the UI.
The User can be mapped to RealmUser and RealmUser can be mapped to User too.

I will have a RealmUserFactory: this contains all the CRUD actions, queries etc. Also, in this class i’m switching to the dedicated realm thread too. You can access it, just only in the managers.

I will have a UserManager: this is the class that you can use everywhere. It calls the UserFactory methods, gets the result in a callback then map the data to the stuct and passes back to the caller.
When you call a manager like this, you need to decide if you need to switch to main thread or not - i dont want to go every call result into the main thread, but if i want i will put it here. This result a better code on the UI-s.

So the calls like this:

UI button: getUserByEmail() -> UserManager.getUserByEmail() -> RealmUserFactory.getUserByEmail() -> RealmManager.getCurrentRealm() return Realm() -> RealmUserFactory Query(), returning RealmUser -> UserManager return Map(from: RealmUser, to: User) -> UI writes userdata on screen


Can I solve it via GCD?


Yeah, i’m using it like the realm documents

// Query and update from any thread
DispatchQueue(label: “realm”).async {
autoreleasepool {
let realm = try! Realm()
let theDog = realm.objects(Dog.self).filter(“age == 1”).first
try! realm.write {
theDog!.age = 3

The get user factory function looks like this:

   public func getUserBy(realmIdentity: String,
                          callback: @escaping (Result<RealmUser?, NSError>) -> Void) {
        DispatchQueue(label: "realm").async {
            autoreleasepool {
                if let realm = try? Realm() {
                    let predicate = NSPredicate(format: "realmIdentity == %@", realmIdentity)
                    let userList = realm.objects(RealmUser.self).filter(predicate)
                } else {
                            NSError(domain: "",
                                    code: 0,
                                    userInfo: [NSLocalizedDescriptionKey: "RealmUserFactory.Realm doesnt exist"])))