Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you compact a Realm DB on iOS?

Tags:

ios

swift

realm

I'd like to compact a Realm instance on iOS periodically to recover space. I think the process is to copy the db to a temporary location, then copy it back and use the new default.realm file.

My problem is Realm() acts like a singleton and recycles objects so I can't really close it and tell it to open the new default.realm file.

The docs here (https://realm.io/docs/objc/latest/api/Classes/RLMRealm.html) suggest I wrap all the Realm() calls in autorelease { } but it can't be this complicated.

like image 271
Jason Leach Avatar asked Apr 26 '16 23:04

Jason Leach


People also ask

How do I view realm database iOS?

Right-click the downloaded file and "Show Package Contents." You'll find your Realm files under AppData/Documents/mongodb-realm/<app-name>/????? . Find the file for the realm you're interested in and double-click it to open it in Realm Studio.

What is iOS realm database?

Realm is a fast, scalable alternative to SQLite with mobile to cloud data sync that makes building real-time, reactive mobile apps easy. Deploy a sample appView documentation.

How do I close a realm in Swift?

According to the documentation, close is not available in Swift SDK. There is no need to manually close a realm in Swift or Objective-C.

Where is my realm file Xcode?

Copy the database from the emulator/phone to view it. That can be done by using ADB: adb pull /data/data/<packagename>/files/ . That command will pull all Realm files created by Realm.


2 Answers

The answer given by @marius has an issue: the open Realm might still reference the deleted file. This means some writes might end up in the old (deleted) file, causing the app to lose data.

The correct implementation of compactRealm method looks like this (swift 3):

func compactRealm() {
    let defaultURL = Realm.Configuration.defaultConfiguration.fileURL!
    let defaultParentURL = defaultURL.deletingLastPathComponent()
    let compactedURL = defaultParentURL.appendingPathComponent("default-compact.realm")

    autoreleasepool {
        let realm = try! Realm()
        try! realm.writeCopy(toFile: compactedURL)
    }
    try! FileManager.default.removeItem(at: defaultURL)
    try! FileManager.default.moveItem(at: compactedURL, to: defaultURL)
}

This issue has been driving me crazy until I found an answer here

like image 145
adam12 Avatar answered Sep 30 '22 15:09

adam12


It can be indeed tricky to completely tear down all retrieved model accessors, but there is unfortunately no other way to close a Realm.

As you wrote "periodically" every app launch might be often enough, depending on your use case.

On the launch of your application, it should be still relatively easy to open Realm in a dedicated autoreleasepool, write a compacted copy to a different path and replace your default.realm file with it.

Swift 2.1

func compactRealm() {
    let defaultURL = Realm.Configuration.defaultConfiguration.fileURL!
    let defaultParentURL = defaultURL.URLByDeletingLastPathComponent!
    let compactedURL = defaultParentURL.URLByAppendingPathComponent("default-compact.realm")

    autoreleasepool {
        let realm = try! Realm()
        realm.writeCopyToPath(compactedURL)
    }
    try! NSFileManager.defaultManager().removeItemAtURL(defaultURL)
    try! NSFileManager.defaultManager().moveItemAtURL(compactedURL, toURL: defaultURL)
}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    compactRealm()

    // further setup …

    return true
}

Swift 3.0

func compactRealm() {
    let defaultURL = Realm.Configuration.defaultConfiguration.fileURL!
    let defaultParentURL = defaultURL.deletingLastPathComponent()
    let compactedURL = defaultParentURL.appendingPathComponent("default-compact.realm")

    autoreleasepool {
        let realm = try! Realm()
        try! realm.writeCopy(toFile: compactedURL)
    }
    try! FileManager.default.removeItem(at: defaultURL)
    try! FileManager.default.moveItem(at: compactedURL, to: defaultURL)
}

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    compactRealm()

    // further setup …

    return true
}
like image 40
marius Avatar answered Sep 30 '22 16:09

marius