Как работать с существующей базой данных SQLite в iOS?

Недавно я начал проект iOS, и мне нужно работать с автономной базой данных, которая будет загружаться из Интернета при наличии обновлений. Это мой первый проект для iOS, поэтому я пытаюсь заставить работать функциональность, прежде чем разрабатывать механизм загрузки.

Я выбрал оболочку SQLite SWLite.swift (https://github.com/stephencelis/SQLite.swift), и мои запросы и табличные представления готовы к работе. Но я не могу подключиться к БД. Я пробовал почти все остальные вопросы/ответы здесь, но безуспешно.

Например, я поместил базу данных SQLite в Assets.xcassets и попробовал let path = Bundle.main.path(forResource: "myDb", ofType: "db")!, и приложение вышло из строя (когда я получил nil обратно - предположительно, из-за того, что путь не мог быть найден). Точно так же я попробовал то, что предлагали другие, в том числе создал папку на моем Mac, поместил в нее файл, добавил .bundle к имени папки и поместил его в активы... снова nil.

Может ли кто-нибудь посоветовать? Я просмотрел Apple Docs и не смог найти то, что искал - опять же, это мой первый раз, поэтому, возможно, я делаю это неправильно.


person The48Percent    schedule 02.07.2017    source источник


Ответы (3)


1.: Получите правильный путь к файлу базы данных

Похоже, ваша основная проблема заключалась в том, чтобы получить правильный путь к файлу базы данных. Я не смог найти способ заставить его работать, если файл базы данных также находится в активах. Поэтому не сохраняйте файл базы данных в папке «Активы», а добавьте его в список Ресурсы пакета копирования в настройке Фазы сборки текущей цели.< /strong> Если ваш файл называется myDb.db, вы можете получить правильный путь следующим образом:

let dbUrl = Bundle.main.url(forResource: "myDb", withExtension: "db")!
let dbPath = dbUrl.path

2.: Доступ к вашей базе данных (без ее копирования)

Теперь можно получить доступ к вашей базе данных без необходимости (вручную?) копировать ее. Просто используйте уже упомянутый библиотека SQLite.swift:

db = try! Connection(dbPath)

Примечания. Поскольку вопрос уже немного устарел, возможно, на момент запроса не было возможности получить доступ к файлу базы данных таким образом. Тем не менее, это работает до сих пор. Единственное, что я еще не проверил явно, это запись в базу данных. По крайней мере, доступ только для чтения работает как шарм.

person Johnson_145    schedule 13.12.2018
comment
Я тестировал это по крайней мере с iOS 10+. - person Johnson_145; 06.04.2021

Вы не можете напрямую читать из пакетов sqlite файлы на своем телефоне. Вы должны сначала скопировать его в папку «Документы» и начать читать оттуда. Это нужно сделать только один раз. Чтобы переместить его,

let path = Bundle.main.path(forResource: "DBName", ofType: "sqlite")
do{
    try fileManger.copyItem(atPath: path!, toPath: dbPath)
}catch let error as NSError {
    print("error occurred, here are the details:\n \(error)")
}

Затем для подключения вы можете использовать

let doumentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let dbPath = doumentDirectoryPath.appendingPathComponent("DBName.sqlite")
person Fangming    schedule 02.07.2017
comment
@The48Percent dbPath — это путь в строковом формате к вашему файлу SQLite в папке «Документ». Вы можете использовать свою библиотеку SQLite, чтобы прочитать файл оттуда. - person Fangming; 02.07.2017
comment
Не могли бы вы привести пример того, каким должно быть dbPath? Приложение аварийно завершает работу в операторе try с fatal error: unexpectedly found nil while unwrapping an Optional value. Код был смесью того, что вы предложили: try fileManager.copyItem(atPath: path!, toPath: "myDb.sqlite") - person The48Percent; 02.07.2017
comment
@The48Percent Используйте dbPath во втором примере. - person Fangming; 02.07.2017
comment
Проблема в вашем коде заключается в том, что вам нужно скопировать путь к папке с документами, поэтому вам не хватает всех папок предыдущего уровня. Идея здесь в том, что вам нужно получить фактический путь к файлу в основном пакете, а затем полный путь к файлу в папке документов. Скопируйте файл в папку с документами и в дальнейшем читайте оттуда. - person Fangming; 02.07.2017
comment
Это должен быть путь в ресурсах, так как он не может найти файл. Я открыл файл, расположенный в Assets, с помощью Finder, и, похоже, он поместил файл в каталог myDB.dataset со следующим содержимым: Contents.json и myDB.sqlite. Какое имя и расширение я использую для параметра forResource? - person The48Percent; 02.07.2017
comment
@ The48Percent Я имею в виду, что в любом случае вы должны скопировать его в папку «Документ», чтобы использовать его, без исключений. Таким образом, вы можете либо найти путь к файлу в папке assets, либо просто поместить его в основной пакет. Не забудьте добавить его в Copy Bundle Resources из настроек сборки, если вы используете основной пакет. - person Fangming; 03.07.2017

Во-первых, вы никогда не захотите иметь свою базу данных где-либо еще, кроме как в папке «Документы».

Вот процесс работы с SQLite.Swift: -

 // this is the path where your DB should be

 let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first! 


// this is how you create a DB with a table:- 

    do {
                let db_name = "my_db"
                let db = try Connection("\(path)" + "/" + db_name! + ".sqlite3")
                try db.key("12345") // if db is encrypted with SQLCipher

                do {
                    try db.run(mastertableName.create(ifNotExists: true) { t in

                        t.column(database_name)
                        t.column(email, unique: true)
                        t.column(date_created)
                        t.column(device_info)
                    })
                }
                catch {

                    print("Creating Master Table Failed!")
                }

Просто установив соединение, он создаст для вас БД, если она не существует!!

Чтение БД: -

do {
        let db_name = "my_db"
        let db = try Connection("\(path)" + "/" + db_name! + ".sqlite3")
        try db.key("12345")

    // db is now open... do your stuff..
}

catch {
print("opening the db failed!")
}
person Dark Innocence    schedule 02.07.2017