1

I am using SQLite.swift framework for my iOS application. I have DatabaseService class where I create a database connection and perform all CURD operations. I was instantiating this class and creating a connection on each controller but recently I changed the database variable to static and create connection once for all controllers. I am not sure if it's a good practice. Here is how I perform this:

static var db: Connection?

init() {
    if DatabaseService.db != nil {
        return
    }
    let path = NSSearchPathForDirectoriesInDomains(
        .documentDirectory, .userDomainMask, true
        ).first!
    do {
        let fileManager = FileManager()
        try fileManager.copyfileToUserDocumentDirectory(forResource: "db", ofType: "sqlite3")

        // Empty database will be created if file does not exist
        DatabaseService.db = try? Connection("\(path)/db.sqlite3")

        print("Connection successful")
    } catch let error {
        print("Unable to connect with the database. \(error)")
    }
}
Maihan Nijat
  • 9,054
  • 11
  • 62
  • 110

1 Answers1

4

I guess the real answer is: if you know what you're doing and you have a good handle on how to do it safely, then sure.

But since you're asking: my answer is no.

The static variable you're showing here is the singleton pattern if you use it everywhere. The singleton pattern often feels like the right thing to do, but the moment you start adding threads and you want to use a different data provider, things start getting buggy, more complicated, and ugly. You're better off using dependency injection with the factory pattern using an object you instantiated just once.

It's really not much more code to do it that way. The choice just becomes when you want to inject it (compile time or runtime), and Swift makes this all pretty easy. Let me know if you want an edit with an example. It's a bit more code to do it this way up front, but in the long run for most situations, it will save you so much heartache. Do some research about the pros and cons of the singleton. Most agree it's a bad idea in most situations.

I'm going to add a passage from a book which I HIGHLY RECOMMEND:

Major problems can be caused by global states, for example, the usage of Singletons or static members in your unit under test. Not only is it that Singletons increase the coupling between software units. They also often hold a global state that circumvents unit test independence. For instance, if a certain global state is the precondition for a successful test, but the previous test has mutated that global state, it can cause serious trouble. Especially in legacy systems, which are often littered with Singletons, this begs the question: how can I get rid of all those nasty dependencies to those Singletons and make my code better testable? Well, that’s an important question I discuss...

This book also goes on to cite an interview with the authors of the iconic book Design Patterns where the authors basically say they wouldn't mind dropping the singleton pattern, because it's never used correctly.

The authors of an iconic and influential book about abstract design patterns joke (I think it's a joke) about dropping the singleton design pattern from a newly revised version of their book...

Maybe the real answer really is always no.

Benjamin
  • 1,832
  • 1
  • 17
  • 27
  • 2
    Agreed. They could make a wrapper class with methods for db operations, and pass this utility class (via initializers, segues, etc, choose your way) to objects who need it. Or access it via delegate pattern. There's so many better options than static/singleton. Also db access is critical so you don't want to expose it to your whole app anyway. – Eric Aya Jun 03 '18 at 16:41
  • @Moritz I feel like I can now count myself as one of the many who now did a great service to the industry by making a post warning about the singleton. I hope thousands of eyes see my post and your comment... Today is a good day... – Benjamin Jun 03 '18 at 17:21