Alex Cowley
Alex Cowley

Reputation: 123

How to create a pre bundled realm file and upload data to it?

I am new to Realm and I want to ship a pre bundled Realm file my app, however the realm documentation is unclear to me on how to actually create a .realm file and also upload the desired pre bundled data to it. I have not been able to find any solution via SO, Google, or Youtube. Step-by-step instructions would be very helpful.

Upvotes: 3

Views: 2580

Answers (1)

TiM
TiM

Reputation: 16021

We're still looking at ways to officially make generating pre-populated Realms more easy. It's definitely a desired feature for the Realm Browser, but due to the way that Realm files require a migration when changing the schema, it's somewhat tricky to incorporate into a UI. It's definitely something we want to improve down the line.

At the moment, the Browser has a converter in it that can perform minimal data import like CSV files.

The Realm documentation is saying that the easiest way for you to produce a pre-populated Realm specific for your apps needs is to build a separate macOS app whose sole role is to generate the Realm file, pre-populate the data and then expose the resulting Realm file so you can copy it to your app.

The operation to do this is just like any normal Realm interaction (try! Realm() is what causes the file to actually be initially created), except you manually interact with the Realm file on disk upon completion.

I'm working on an app for an iOS conference, and the schedule data for the event is going to be stored in a Realm that is pre-bundled with the app when it ships.

Since I thought creating an extra macOS app would be overkill for an iOS app, I instead used iOS unit tests that would generate the pre-bundled Realm from scratch every time it was executed.

class Tests: XCTestCase {
    func testGenerateNewDefaultRealm() {
        let sources = [conferences, sponsors, conferenceDays] as [Any]
        XCTAssert(generateDefaultRealm(named: "MyConferenceRealm.realm", sources: sources))
    }
}

extension Tests {
    public func generateDefaultRealm(named name: String, sources: [Any]) -> Bool {
        // Create and configure the Realm file we'll be writing to
        let realm = generateRealm(named: name)

        // Open a Realm write transaction
        realm.beginWrite()

        // Loop through each source and add it to Realm
        for source in sources {
            if let objectArray = source as? [Object] {
                for object in objectArray {
                    realm.add(object)
                }
            }
            else if let objectDictionary = source as? [String : Object] {
                for (_, object) in objectDictionary {
                    realm.add(object)
                }
            }
        }

        // Commit the write transaction
        do {
            try realm.commitWrite()
        }
        catch let error {
            print(error.localizedDescription)
            return false
        }

        // Print the file location of the generated Realm
        print("=====================================================================")
        print(" ")
        print("Successfully generated at")
        print(realm.configuration.fileURL!.path)
        print(" ")
        print("=====================================================================")

        return true
    }

    public func generateRealm(named name: String) -> Realm {
        let exportPath = NSTemporaryDirectory()
        let realmPath = exportPath.appending(name)

        // Delete previous Realm file
        if FileManager.default.fileExists(atPath: realmPath) {
            try! FileManager.default.removeItem(atPath: realmPath)
        }

        // Create new Realm file at path
        let objectTypes: [Object.Type] = [Conference.self, ConferenceDay.self, SessionBlock.self, Event.self, Presentation.self,
                                          Session.self, Location.self, Speaker.self, Sponsor.self, Venue.self]
        let configuration = Realm.Configuration(fileURL: URL(string: realmPath), objectTypes: objectTypes)
        let realm = try! Realm(configuration: configuration)
        return realm
    }
}

Running this unit test will generate a new Realm file in the NSTemporaryDirectory() directory of the Mac, and then feed in a set of Array and Dictionary objects of un-persisted Realm Object instances that are created each time the test is run. The location of the final Realm is then printed in the console so I can grab it and move it to the app bundle.

Upvotes: 6

Related Questions