2

I detect whether a connection exists on a Singleton instance and if it doesn't it will open up a new connection on app start up. 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.

The way I have the code now it defeats the purpose of having a shared Singleton because I just access the static connection object. 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'

Non-working code

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")
    }
}

How can you call a private function within a Singleton class on init and assign it to some variable?

Current working code

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 app init

@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")
        }
    }
    ....
}
4
  • 1
    Will dbPath change often or is it always the same? If it is the same you could call the method from init. Commented Nov 24, 2021 at 21:12
  • @JoakimDanielson dbPath will always be the same Commented Nov 24, 2021 at 21:14
  • 1
    Then remove the parameter in open and call it from init Commented Nov 24, 2021 at 21:24
  • @JoakimDanielson thank you I'll try it this way Commented Nov 24, 2021 at 21:31

1 Answer 1

1

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'

That makes sense considering how you're using open:

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

Right now, open is a static method of DBConnection, which means that you can call it without needing an instance of the class. It's similar to a "class method" in Objective-C. But in your broken code, you have:

var conn: Connection? = nil

so conn is an instance variable, i.e. a variable that only exists in the context of an instance of the class. A quick fix would be to make open non-static:

func open(dbPath: URL) throws {

and then call it using the shared instance:

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

(Note the shared added there.)

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.

You could call open from inside the initializer if you want the connection to open when the singleton is created.

Another direction you could go is to leave conn and open both static so that open can access conn, and let the class itself be the singleton. Then you could eliminate the shared variable.

However, I think the best option would be to do as described above, making conn and open non-static, and get rid of the shared instance and instead just keep track of the DBConnection object that you create.

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome! Thanks for this in depth explanation of each piece.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.