在 Swift 中使用单例模式创建全局 SQLite 数据库连接

Creating a global SQLite DB Connection with Singleton pattern in Swift

我检测 Singleton 实例上是否存在连接,如果不存在,它将在应用程序启动时打开一个新连接。但是,理想情况下,我希望 open 函数在首次创建 Singleton 时触发,而不必显式调用它并将其分配给 class.

中的某个变量

我现在拥有代码的方式违背了共享单例的目的,因为我只是访问静态连接对象。当我尝试将静态 conn 更改为实例变量时,出现错误 Instance member 'conn' cannot be used on type 'DBConnection'

无效代码

class DBConnection {
    static let shared = DBConnection()
    var conn: Connection? = nil
    
    private init() { }
    
    static func open(dbPath: URL) throws {
        var dbConnections: [Connection] = []
        
        do {
            let dbConnection = try Connection("\(dbPath)/db.sqlite3")
            dbConnections.append(dbConnection)
            print("found connection, \(dbConnections)")
        } catch {
            throw SQLiteDBError.couldNotOpenConnection
        }
        
        self.conn = dbConnections[0]
        print("successfully opened connection")
    }
}

如何在初始化时调用单例 class 中的私有函数并将其分配给某个变量?

当前工作代码

class DBConnection {
    static let shared = DBConnection()
    static var conn: Connection?
    
    private init() { }
    
    static func open(dbPath: URL) throws {
        var dbConnections: [Connection] = []
        
        do {
            let dbConnection = try Connection("\(dbPath)/db.sqlite3")
            dbConnections.append(dbConnection)
            print("found connection, \(dbConnections)")
        } catch {
            throw SQLiteDBError.couldNotOpenConnection
        }
        
        self.conn = dbConnections[0]
        print("successfully opened connection")
    }
}

主应用初始化

@main
struct MyApp: App {
    
    init() {
        if DBConnection.conn != nil {
            do {
                try DBConnection.open(dbPath: FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)[0])
            } catch {
                print("error")
            }
        } else {
            print("Connection already existed")
        }
    }
    ....
}

When I attempt to change the static conn to an instance variable I get the error Instance member 'conn' cannot be used on type 'DBConnection'

考虑到您的使用方式,这是有道理的 open:

try DBConnection.open(dbPath: FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)[0])

现在,openDBConnection 的静态方法,这意味着您可以调用它而无需 class 的实例。它类似于 Objective-C 中的“class 方法”。但是在您损坏的代码中,您有:

var conn: Connection? = nil

所以conn是一个实例变量,即只存在于class实例上下文中的变量。一个快速的解决方法是使 open 成为非静态的:

func open(dbPath: URL) throws {

然后使用共享实例调用它:

try DBConnection.shared.open(dbPath: FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)[0])

(注意那里添加的 shared。)

However, ideally I'd like for the open function to fire when the Singleton is first created without having to explicitly call it and assign it to some variable within the class.

如果您希望在创建单例时打开连接,您可以从初始化器内部调用 open

您可以走的另一个方向是让 connopen 都保持静态,以便 open 可以访问 conn,并让 class 本身成为单身人士。然后你可以消除 shared 变量。

但是,我认为最好的选择是按照上述方式进行,使 connopen 成为非静态的, 摆脱shared 实例,而只是跟踪您创建的 DBConnection 对象。