如何在iOS上压缩Realm数据库?

9
我希望能够定期压缩iOS上的Realm实例以恢复空间。我认为这个过程是将数据库复制到临时位置,然后将其复制回来并使用新的default.realm文件。
我的问题是Realm()表现得像一个单例并且循环利用对象,因此我无法真正关闭它并告诉它打开新的default.realm文件。
这里的文档(https://realm.io/docs/objc/latest/api/Classes/RLMRealm.html)建议我在autorelease { }中包装所有的Realm()调用,但这不能这么复杂。
3个回答

22

完全撤销所有已检索的模型访问者确实是有难度的,但不幸的是没有其他关闭Realm的方法。

正如您所写的“定期”,根据您的用例,每次应用程序启动可能足够频繁。

在启动应用程序时,仍然相对容易在专用的autoreleasepool中打开Realm,将压缩的副本写入不同的路径,并用其替换默认的realm文件。

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
}

谢谢!autoreleasepool是关键。我已经拥有了其他所有东西,但没有它就会崩溃。非常感谢。 - 0x6A75616E
嘿@suleymancalik,回复晚了很抱歉。在那种情况下没有什么可以压缩的方法,但同时第一次陷入这种情况应该是非常困难的。所以我想知道你为什么会担心这个问题/你是如何陷入这种情况的? - marius
2
请确保您在本页面其他地方建议的经过调整的版本。调用 removeItem() 和 moveItem() 必须发生在自动释放池之外,以确保 Realm 对象已被解除分配。 - Eli Burke
2
@EliBurke:感谢您的建议。我编辑了我的答案以反映在代码中。 - marius
嗨@marius 在DidFinish启动时调用这个函数会延迟应用程序的启动时间。 - Jitendra
显示剩余2条评论

8

@marius提供的答案存在问题:打开的Realm可能仍然引用已删除的文件。这意味着一些写入可能会在旧(已删除)文件中结束,导致应用程序丢失数据。

compactRealm方法的正确实现如下(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)
}

这个问题一直困扰着我,直到我在这里找到了答案。


3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接