在Swift Storyboard中创建和打开SQLite数据库及其表的位置

e0bqpujr  于 2022-11-28  发布在  Swift
关注(0)|答案(1)|浏览(126)

我目前正在通过import sqlite3使用SQLite开发一个iOS应用程序。我遵循了Kodeco的SQLite With Swift Tutorial: Getting Started-但我有一些问题,因为他们使用的是操场。
在哪里创建数据库文件和表?

public class SQLiteDatabase {

    public static var currentAccount = Account(id: -1, email: "", name: "", lastname: "", gender: "", birthday: Date(), creationDate: Date())
    public static let pathExtension = "xPose.sqlite"
    public static var path: String!
    
    private let dbPointer: OpaquePointer?
    private init(dbPointer: OpaquePointer?) {
        self.dbPointer = dbPointer
    }
    
    deinit {
        sqlite3_close(dbPointer)
    }
    
    fileprivate var errorMessage: String {
        if let errorPointer = sqlite3_errmsg(dbPointer) {
            let errorMessage = String(cString: errorPointer)
            return errorMessage
        } else {
            return "No error message provided from sqlite."
        }
    }
    
    func enableForeignKeys() {
        if sqlite3_exec(dbPointer, "PRAGMA foreign_keys = ON", nil, nil, nil) != SQLITE_OK {
            let err = String(cString: sqlite3_errmsg(dbPointer))
                print("error attempting to enable foreign keys: \(err)")
            }
    }
    
    func createFile() {
        do {
            let url = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(SQLiteDatabase.pathExtension)
            SQLiteDatabase.path = url.absoluteString
            print("File created")
        }
        catch {
            print("Error creating file")
        }
    }
    
    func createTables() {
        do {
            try createTable(table: Account.self)
            try createTable(table: Measurement.self)
            try createTable(table: Posture.self)
            try createTable(table: Vital.self)
            try createTable(table: Mood.self)
        } catch {
            print("Failed to create Tables")
        }
    }
    
    // Open the databse
    static func open(path: String) throws -> SQLiteDatabase {
        var db: OpaquePointer?
        
        if sqlite3_open(path, &db) == SQLITE_OK {
            return SQLiteDatabase(dbPointer: db)
        } else {
            defer {
                if db != nil {
                    sqlite3_close(db)
                }
            }
            if let errorPointer = sqlite3_errmsg(db) {
                let message = String(cString: errorPointer)
                throw SQLiteError.OpenDatabase(message: message)
            } else {
                throw SQLiteError.OpenDatabase(message: "No error message provided from sqlite.")
            }
        }
    }
    
    func prepareStatement(sql: String) throws -> OpaquePointer? {
        var statement: OpaquePointer?
        guard sqlite3_prepare_v2(dbPointer, sql, -1, &statement, nil) == SQLITE_OK else {
            throw SQLiteError.Prepare(message: errorMessage)
        }
        return statement
    }
    
    func createTable(table: SQLTable.Type) throws {
        let createTableStatement = try prepareStatement(sql: table.createStatement)
        defer {
            sqlite3_finalize(createTableStatement)
        }
        
        guard sqlite3_step(createTableStatement) == SQLITE_DONE else {
            throw SQLiteError.Step(message: errorMessage)
        }
        print ("\(table) table created.")
    }

我尝试将其放入私有init方法中,但每次我尝试打开数据库时,它都会尝试创建新的文件和表,并且在目录中没有创建数据库文件。

r8xiu3jd

r8xiu3jd1#

在调用sqlite3_open之前,需要查看path中的数据库文件是否存在。如果不存在,则需要在打开数据库文件后调用createTables
这样,在您首次尝试打开数据库时,一切都已设置好。
大概是这样的:

// Open the databse
static func open(path: String) throws -> SQLiteDatabase {
    var db: OpaquePointer?
    
    let exists = FileManager.default.fileExists(atPath: path)
    if sqlite3_open(path, &db) == SQLITE_OK {
        if !exists {
            createTables()
        }
        return SQLiteDatabase(dbPointer: db)
    } else {
        defer {
            if db != nil {
                sqlite3_close(db)
            }
        }
        if let errorPointer = sqlite3_errmsg(db) {
            let message = String(cString: errorPointer)
            throw SQLiteError.OpenDatabase(message: message)
        } else {
            throw SQLiteError.OpenDatabase(message: "No error message provided from sqlite.")
        }
    }
}

每次启动应用时,只需调用open一次。

相关问题