【问题标题】:Swift Realm. How to put 3 millions objects in database迅捷领域。如何将 300 万个对象放入数据库
【发布时间】:2019-03-02 08:28:58
【问题描述】:

我制作离线词典应用程序。现在我将字典文件转换为领域数据库。

转换函数:

if let path = Bundle.main.path(forResource: "dictionary", ofType: "dsl") {
        do {
            let data = try String(contentsOfFile: path, encoding: .utf8)
            let myStrings = data.components(separatedBy: .newlines)

            for (index, row) in myStrings.enumerated() {

                if(row.containsChineseCharacters)
                {
                    let firstWord = CNDict()
                    firstWord.word = row
                    firstWord.pinyin = myStrings[index+1]
                    firstWord.translate = myStrings[index+2]

                    try! realm.write {
                        realm.add(firstWord)
                    }
                }
            }
            print("The task end.")
        } catch {
            print(error)
        }
     }

当我尝试立即转换字典时,数据库文件变成很多 GB 并在中间崩溃

将字典分成几部分不是一种选择,因为大约有 300 万行。这将花费很多......(领域插件崩溃)

我需要关于如何在我们的崩溃中向数据库添加尽可能多的值的帮助。

【问题讨论】:

  • 上下文是什么,每个用户的手机上是否都有一个 300 万元素的字典,当他们更新时将转换为他们自己的领域数据库?是否有可能在服务器上预填充数据库?
  • 请分享CNDictRealm模型看看是否正确。另一件事是 Fatal error: Index out of range,因为 lastindex+1index+2 可能会增加。
  • 这个问题有点含糊。通常,在发布问题时,最好包含详细信息,以便我们了解用例。例如,什么是字典文件?你的数据结构是什么?正如之前的评论中提到的, index+1 没有任何上下文,所以我们不知道那是什么。什么是 CNDict? 3M 线有点多,可能会使设备过载,你能把数据分成块而不是一次全部读取吗?也许逐行处理文件?请花点时间查看:How do I ask a good question?.

标签: ios swift database realm


【解决方案1】:

问题是您的文件很大,此时您将其加载到内存中:

        let data = try String(contentsOfFile: path, encoding: .utf8)

然后你将这里的内存占用加倍:

        let myStrings = data.components(separatedBy: .newlines)

所以我的猜测是你从系统收到了内存不足的信号。

您可以使用lazy 集合,而不是将所有数据加载到内存中并将其翻倍。它只会在需要写入时读取和解析行。它不会一次加载所有行。 Swift 中惰性集合的一个缺点是它们无法提供我们习惯的所有功能。

这里是解决您问题的游乐场的完整代码。您可以并且也许应该优化它的某些部分,但无论如何它只是展示了如何使用lazy 集合来完成它。 (我改变了一些名字,但它仍然是你想要的)。

import Foundation

extension String {
    var containsOneSymbol: Bool {
        return contains("1")
    }
}

extension Character {
    var isNewLine: Bool {
        let string = String(self)
        let set = CharacterSet(charactersIn: string)

        return !set.isDisjoint(with: CharacterSet.newlines)
    }
}


/// Add Object subclass for Realm
@objcMembers
final class CNDict {
    dynamic var word = ""
    dynamic var pinyin = ""
    dynamic var translate = ""
}

final class ModelWriterWrapper {
    private let bufferCapacity = 3
    private var buffer: [String] = []
    init() {
        buffer.reserveCapacity(bufferCapacity)
    }

    func proccess(line: String) {
        guard buffer.count == bufferCapacity else {
            assert(buffer.count < bufferCapacity, "Buffer failer count: \(buffer.count)!")
            buffer.append(line)
            return
        }

        if let firstLine = buffer.first, firstLine.containsOneSymbol {
            let dict = CNDict()
            dict.word = firstLine
            dict.pinyin = buffer[1]
            dict.translate = buffer[2]

            print("Ready for writing into DB \n word: \(dict.word) pinyin: \(dict.pinyin) translate: \(dict.translate)")
        }

        buffer.removeFirst()
        buffer.append(line)
    }
}

let data = stride(from: 0, to: 100_000, by: 1).map { "Line number \($0)\n"}.joined()

var line: String = ""
let myLines = data.lazy.map { char -> String in
    line.append(char)
    guard !char.isNewLine else {
        defer { line = "" }
        return line
    }

    return ""
}.filter { !$0.isEmpty }


let databaseWritter = ModelWriterWrapper()

myLines.forEach {
    databaseWritter.proccess(line: $0)
}

如果对代码有任何疑问,请询问。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 1970-01-01
    相关资源
    最近更新 更多