Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a Swift Class Singleton instance thread safe?

I have a singleton class as so:

class Database {
   static let instance:Database = Database()
   private var db: Connection?

   private init(){
      do {
        db = try Connection("\(path)/SalesPresenterDatabase.sqlite3")
        }catch{print(error)}
   }
}

Now I access this class using Database.instance.xxxxxx to perform a function within the class. However when I access the instance from another thread it throws bizarre results as if its trying to create another instance. Should I be referencing the instance in the same thread?

To clarify the bizarre results show database I/o errors because of two instances trying to access the db at once

Update
please see this question for more info on the database code: Using transactions to insert is throwing errors Sqlite.swift

like image 630
Richard Thompson Avatar asked Apr 13 '17 13:04

Richard Thompson


People also ask

How do I create a thread-safe singleton class in Swift?

You can create a thread safe singleton using DispatchQueue. We will create a serial queue and add a sync method to set and get value. Below is the code you can achieve thread safe singleton class. It will write an another blog where we can improve the performance using dispatch barrier.

How can a singleton class be thread-safe?

Thread Safe Singleton in JavaCreate the private constructor to avoid any new object creation with new operator. Declare a private static instance of the same class. Provide a public static method that will return the singleton class instance variable.

Why singleton is not thread-safe in Swift?

Additionally, singletons should be protected against concurrent usage in order to avoid synchronisation issues, and thread safe singletons could lead to a performance bottleneck if they're being used by multiple threads in parallel, which can be avoided.

How do you make a class thread-safe in Swift?

In short, this means that the Name class is not thread-safe. To fix the above race condition, we need to synchronize how threads get to access and modify the state of this class. If we make it so that Thread 2 cannot start running setFullName until Thread 1 finishes doing so, the scenario above would become impossible.


2 Answers

class var shareInstance: ClassName {

    get {
        struct Static {
            static var instance: ClassName? = nil
            static var token: dispatch_once_t = 0
        }
        dispatch_once(&Static.token, {
            Static.instance = ClassName()
        })
        return Static.instance!
    }
}

USE: let object:ClassName = ClassName.shareInstance

Swift 3.0

class ClassName {
  static let sharedInstance: ClassName = { ClassName()} ()
}

USE: let object:ClassName = ClassName.shareInstance

like image 68
Dhananjay Patil Avatar answered Nov 15 '22 16:11

Dhananjay Patil


In Swift 3.0 add a private init to prevent others from using the default () initializer.

class ClassName {
  static let sharedInstance = ClassName()
  private init() {} //This prevents others from using the default '()' initializer for this class.
}
like image 25
Richard Hope Avatar answered Nov 15 '22 15:11

Richard Hope