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

时间:2017-03-07 16:25:00

标签: sqlite swift3 xcode8 fmdb

我使用Swift3和Xcode8创建了一个应用程序,并使用FMDB作为我的数据库,当它在模拟器上运行时,它可以从data.db获取数据,但是当它在通用设备上运行时(这是我的手机),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的新手,请解释一下,我会尽我所能。非常感谢!!!!

编辑: 下载手机中的内容后,数据库为空白。在我丢失错误之后,它会显示

enter image description here

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

1 个答案:

答案 0 :(得分:0)

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

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

就个人而言,我建议使用Xcode的“设备”窗口并下载应用程序包(请参阅https://stackoverflow.com/a/38064225/1271826)并查看数据库。我敢打赌这是一个空白的数据库,根本没有定义表格。就原因而言,可能是因为你做了一些早期的测试,而且在Documents文件夹中有一个旧版本的数据库。尝试从设备中完全删除该应用并重新运行,看看是否可以修复它。

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

但是,就像我说的那样,我们是盲目的,直到(a)你为你的代码添加了一些错误处理,这样你才能看出它失败的原因; (b)查看设备上的数据库,看看它是什么样的。