如何在通用 iOS 设备而不是模拟器上使用 FMDB?

How to use FMDB on the generic iOS device instead of simulator?

我使用 Swift3 和 Xcode8 创建了一个应用程序,并使用 FMDB 作为我的数据库,当它在模拟器上运行时它可以从 data.db 获取数据,但是当它在通用设备(我的phone)上运行时,tableView 中没有数据,也无法插入记录。我在项目中添加了data.db,但是当我在模拟器上更改记录时,data.db中的记录没有改变,但我打印了路径,它指向模拟器文件夹,该文件夹中的数据库会随之改变模拟器中的修改和该文件夹的路径几乎每次都会更改。我很困惑,那是因为我实际上没有连接到我的数据库吗?

这里是 Utility.Swift,它包含常用且经常重复使用的函数

import UIKit

class Utility: NSObject {

class func getPath(_ fileName: String) -> String {
    let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let fileURL = documentsURL.appendingPathComponent(fileName)
    print(fileURL.path)
    return fileURL.path
    }

class func copyFile(_ fileName: NSString){

    let dbPath: String = getPath(fileName as String)
    let fileManager = FileManager.default

    if !fileManager.fileExists(atPath: dbPath) {
        let documentsURL = Bundle.main.resourceURL
        let fromPath = documentsURL!.appendingPathComponent(fileName as String)

        var error : NSError?
        do {
            try fileManager.copyItem(atPath: fromPath.path, toPath: dbPath)
        }
        catch let error1 as NSError {
            error = error1
        }
        let alert: UIAlertView = UIAlertView()
        if (error != nil) {
            alert.title = "Error Occured"
            alert.message = error?.localizedDescription
        }
        else {
            alert.title = "Successfully Copy"
            alert.message = "Your database copy successfully"
        }
        alert.delegate = nil
        alert.addButton(withTitle: "Ok")
        alert.show()
        }
    }

class func invokeAlertMethod(_ strTitle: NSString, strBody: NSString, delegate: AnyObject?) {
    let alert: UIAlertView = UIAlertView()
    alert.message = strBody as String
    alert.title = strTitle as String
    alert.delegate = delegate
    alert.addButton(withTitle: "Ok")
    alert.show()
    }  
}

并且 StudentDataBase.swift 包含查询语言

import UIKit
let sharedInstance = StudentDataBase()

class StudentDataBase : NSObject {

var database: FMDatabase? = nil

class func getInstance() -> StudentDataBase{

    if((sharedInstance.database) == nil)
    {
        sharedInstance.database = FMDatabase(path: Utility.getPath("data.db"))
    }
    return sharedInstance
}


func addStuData(_ student: Student) -> Bool{

    sharedInstance.database!.open()

    let isInserted = sharedInstance.database!.executeUpdate("INSERT INTO [Student info] (StudentID, FirstName, LastName, PhoneNumber) VALUES (?, ?, ?, ?)", withArgumentsIn: [student.studentID, student.fstName, student.lstName, student.phoneNum])

    sharedInstance.database!.close()
    return isInserted
}


func updateStuData(_ student: Student) -> Bool {

    sharedInstance.database!.open()

    let isUpdated = sharedInstance.database!.executeUpdate("UPDATE [Student info] SET FirstName=?, LastName=?, PhoneNumber=? WHERE StudentID=?", withArgumentsIn: [student.fstName, student.lstName, student.phoneNum, student.studentID])
    print(student)
    print(isUpdated)
    sharedInstance.database!.close()
    return isUpdated
}


func deleteStuData(_ student: Student) -> Bool {

    sharedInstance.database!.open()

    let isDeleted = sharedInstance.database!.executeUpdate("DELETE FROM [Student info] WHERE StudentID=?", withArgumentsIn: [student.studentID])

    sharedInstance.database!.close()
    return isDeleted
}

func getAllStuData() -> [Student] {

    sharedInstance.database!.open()

    let resultSet: FMResultSet! = sharedInstance.database!.executeQuery("SELECT * FROM [Student info]", withArgumentsIn: nil)
    var marrStudentInfo : [Student] = []
    if (resultSet != nil) {
        while resultSet.next() {
            let student : Student = Student()
            student.studentID = resultSet.string(forColumn: "StudentID")
            student.fstName = resultSet.string(forColumn: "FirstName")
            student.lstName = resultSet.string(forColumn: "LastName")
            student.phoneNum = resultSet.string(forColumn: "PhoneNumber")
            marrStudentInfo.append(student)
        }
    }
    sharedInstance.database!.close()
    return marrStudentInfo
}
}

也在AppDelegate.swift,我写了:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    Utility.copyFile("data.db")
    return true
}

我是 Swift 和 FMDB 的新手,请解释一下,我会尽力 best.Thank 你!!!!

编辑: 在我下载 phone 中的内容后,数据库为空。在我丢弃错误后,它显示

Inserted failed:Optional("no such table: Student info")

SQLite 提供了很好的错误报告,您应该利用它。因此,例如,如果这些 executeUpdate 调用中的任何一个失败,您应该检查 lastErrorMessage(在关闭数据库之前)以便了解失败的原因。

就个人而言,我建议使用 executeQuery(_:values:)executeUpdate(_:values:) 而不是 executeQuery(_:withArgumentsIn:)executeUpdate(_:withArgumentsIn:) 因为前一种方法会抛出错误(这会转变为更活跃的错误来自更被动的处理范例,您必须手动记住检查错误)。但是无论你如何处理错误,都要去做,否则我们都在猜测。

就我个人而言,我建议使用 Xcode 的 "Devices" window 并下载您的应用程序包(参见 )并查看数据库。我敢打赌这是一个空白数据库,根本没有定义任何表。就原因而言,可能是因为您进行了一些较早的测试,并且 Documents 文件夹中存在旧版本的数据库。尝试从设备中完全删除该应用程序,然后重新运行 看看是否可以解决问题。

其他更隐蔽的问题来源包括文件名大写(例如 Data.dbdata.db)。 macOS 文件系统通常会优雅地处理它,因为它(通常)不区分大小写。但是 iOS 设备区分大小写。

但是,就像我说的,我们一直在盲目飞行,直到 (a) 您在代码中添加了一些错误处理,以便您可以看到它失败的原因; (b) 查看设备上的数据库,看看它是什么样子。