Swift - 设备上未包含预填充的 SQLite 数据库
Swift - Pre-populated SQLite database not included on device
我正在尝试在我的物理 iPhone 的构建中包含一个预填充的 SQLite 数据库(带有 FMDB 包装器)。但是,预填充的数据库未包含在物理设备的构建中。
请注意,它在 IOS 模拟器中运行良好,但仅适用于一台模拟器设备。
我已将数据库包含在构建阶段 > 复制捆绑资源中,并在 Link 带库的二进制文件下链接 libsqlite3.dylib。
我需要添加哪些 Swift 代码才能将构建中包含的数据库获取到物理设备?
代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var checkButton: UIButton!
@IBOutlet weak var tests_scroller: UITextView!
var databasePath = NSString()
override func viewDidLoad() {
super.viewDidLoad()
checkButton.setTitle("\u{2610}", forState: .Normal)
checkButton.setTitle("\u{2611}", forState: .Selected)
let filemgr = NSFileManager.defaultManager()
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docsDir = dirPaths[0] as! String
databasePath = docsDir.stringByAppendingPathComponent("vmd_db.db")
let myDatabase = FMDatabase(path: databasePath as String)
if myDatabase.open(){
var arrayData:[String] = []
let query_lab_test = "SELECT lab_test FROM lab_test ORDER BY lab_test ASC"
let results_lab_test:FMResultSet? = myDatabase.executeQuery(query_lab_test, withArgumentsInArray: nil)
while results_lab_test?.next() == true {
if let resultString = results_lab_test?.stringForColumn("lab_test"){
arrayData.append(resultString)
}
}
var multiLineString = join("\n", arrayData)
tests_scroller.text = multiLineString
myDatabase.close()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
更新 - 工作 Swift 2 XCode 中的代码 7 - 使用复制到物理设备的 FMDB 包装器预填充 SQLite 数据库 OK:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tests_scroller: UITextView!
var databasePath = NSString()
override func viewDidLoad() {
super.viewDidLoad()
let sourcePath = NSBundle.mainBundle().pathForResource("vmd_db", ofType: "db")
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String!
let destinationPath = (documentDirectoryPath as NSString).stringByAppendingPathComponent("vmd_db.db")
do {
try NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath)
} catch _ {
}
//read it
let myDatabase = FMDatabase(path: destinationPath as String)
if myDatabase.open(){
var arrayData:[String] = []
let query_lab_test = "SELECT lab_test FROM lab_test ORDER BY lab_test ASC"
let results_lab_test:FMResultSet? = myDatabase.executeQuery(query_lab_test, withArgumentsInArray: nil)
while results_lab_test?.next() == true {
if let resultString = results_lab_test?.stringForColumn("lab_test"){
arrayData.append(resultString)
}
}
let multiLineString = arrayData.joinWithSeparator("\n")
tests_scroller.text = multiLineString
myDatabase.close()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
据我所知,它不应该在任何模拟器/设备上运行,因为您访问的是文档文件夹中的文件。那不在你的包里。
您需要做的是将文件从捆绑包复制到文档目录,然后再尝试在那里打开它:
//path in documents
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docsDir = dirPaths[0]
databasePath = docsDir.stringByAppendingPathComponent("vmd_db.db")
//if not there, copy from bundle
if !filemgr.fileExistsAtPath(databasePath) {
let bundleDatabasePath = NSBundle.mainBundle().pathForResource("vm_db", ofType: "db")
filemgr.copyItemAtPath(bundleDatabasePath, toPath: databasePath)
}
//read it
let myDatabase = FMDatabase(path: databasePath as String)
我遇到了类似的问题;具体来说,在将数据添加到我在 iPhone 模拟器中使用的应用程序之后,我不想再将所有这些数据添加到我的物理 iPhone 设备中。在查看了 IlludimPu36 和 Daij-Djan 提供的解决方案后,我想到了以下方法,我在 App Delegate 的 (AppDelegate.swift) application(didFinishLaunchingWithOptions) 方法的第一行中调用了该方法:
func copyBundledSQLiteDB() {
let sourcePath = NSBundle.mainBundle().pathForResource("filename", ofType: "sqlite")
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String!
let destinationPath = (documentDirectoryPath as NSString).stringByAppendingPathComponent("filename.sqlite")
// If file does not exist in the Documents directory already,
// then copy it from the bundle.
if !NSFileManager().fileExistsAtPath(destinationPath) {
do {
try NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath)
} catch _ {
}
}
}
它似乎有效,并且在调试器中逐步执行方法的每一行看起来 error-free 对于每种情况,当数据库不存在时(即,在删除应用程序后重新安装之后)或重置模拟器),以及数据库是否已经存在。我在物理设备上也得到了相同的结果。
感谢@IlludiumPu36 和@Daij-Djan为此提供tips/answers,我希望这可以帮助其他人。
我正在尝试在我的物理 iPhone 的构建中包含一个预填充的 SQLite 数据库(带有 FMDB 包装器)。但是,预填充的数据库未包含在物理设备的构建中。
请注意,它在 IOS 模拟器中运行良好,但仅适用于一台模拟器设备。
我已将数据库包含在构建阶段 > 复制捆绑资源中,并在 Link 带库的二进制文件下链接 libsqlite3.dylib。
我需要添加哪些 Swift 代码才能将构建中包含的数据库获取到物理设备?
代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var checkButton: UIButton!
@IBOutlet weak var tests_scroller: UITextView!
var databasePath = NSString()
override func viewDidLoad() {
super.viewDidLoad()
checkButton.setTitle("\u{2610}", forState: .Normal)
checkButton.setTitle("\u{2611}", forState: .Selected)
let filemgr = NSFileManager.defaultManager()
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docsDir = dirPaths[0] as! String
databasePath = docsDir.stringByAppendingPathComponent("vmd_db.db")
let myDatabase = FMDatabase(path: databasePath as String)
if myDatabase.open(){
var arrayData:[String] = []
let query_lab_test = "SELECT lab_test FROM lab_test ORDER BY lab_test ASC"
let results_lab_test:FMResultSet? = myDatabase.executeQuery(query_lab_test, withArgumentsInArray: nil)
while results_lab_test?.next() == true {
if let resultString = results_lab_test?.stringForColumn("lab_test"){
arrayData.append(resultString)
}
}
var multiLineString = join("\n", arrayData)
tests_scroller.text = multiLineString
myDatabase.close()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
更新 - 工作 Swift 2 XCode 中的代码 7 - 使用复制到物理设备的 FMDB 包装器预填充 SQLite 数据库 OK:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tests_scroller: UITextView!
var databasePath = NSString()
override func viewDidLoad() {
super.viewDidLoad()
let sourcePath = NSBundle.mainBundle().pathForResource("vmd_db", ofType: "db")
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String!
let destinationPath = (documentDirectoryPath as NSString).stringByAppendingPathComponent("vmd_db.db")
do {
try NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath)
} catch _ {
}
//read it
let myDatabase = FMDatabase(path: destinationPath as String)
if myDatabase.open(){
var arrayData:[String] = []
let query_lab_test = "SELECT lab_test FROM lab_test ORDER BY lab_test ASC"
let results_lab_test:FMResultSet? = myDatabase.executeQuery(query_lab_test, withArgumentsInArray: nil)
while results_lab_test?.next() == true {
if let resultString = results_lab_test?.stringForColumn("lab_test"){
arrayData.append(resultString)
}
}
let multiLineString = arrayData.joinWithSeparator("\n")
tests_scroller.text = multiLineString
myDatabase.close()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
据我所知,它不应该在任何模拟器/设备上运行,因为您访问的是文档文件夹中的文件。那不在你的包里。
您需要做的是将文件从捆绑包复制到文档目录,然后再尝试在那里打开它:
//path in documents
let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docsDir = dirPaths[0]
databasePath = docsDir.stringByAppendingPathComponent("vmd_db.db")
//if not there, copy from bundle
if !filemgr.fileExistsAtPath(databasePath) {
let bundleDatabasePath = NSBundle.mainBundle().pathForResource("vm_db", ofType: "db")
filemgr.copyItemAtPath(bundleDatabasePath, toPath: databasePath)
}
//read it
let myDatabase = FMDatabase(path: databasePath as String)
我遇到了类似的问题;具体来说,在将数据添加到我在 iPhone 模拟器中使用的应用程序之后,我不想再将所有这些数据添加到我的物理 iPhone 设备中。在查看了 IlludimPu36 和 Daij-Djan 提供的解决方案后,我想到了以下方法,我在 App Delegate 的 (AppDelegate.swift) application(didFinishLaunchingWithOptions) 方法的第一行中调用了该方法:
func copyBundledSQLiteDB() {
let sourcePath = NSBundle.mainBundle().pathForResource("filename", ofType: "sqlite")
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String!
let destinationPath = (documentDirectoryPath as NSString).stringByAppendingPathComponent("filename.sqlite")
// If file does not exist in the Documents directory already,
// then copy it from the bundle.
if !NSFileManager().fileExistsAtPath(destinationPath) {
do {
try NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath)
} catch _ {
}
}
}
它似乎有效,并且在调试器中逐步执行方法的每一行看起来 error-free 对于每种情况,当数据库不存在时(即,在删除应用程序后重新安装之后)或重置模拟器),以及数据库是否已经存在。我在物理设备上也得到了相同的结果。
感谢@IlludiumPu36 和@Daij-Djan为此提供tips/answers,我希望这可以帮助其他人。