To test that your Singleton is Thread safe I've made a little sample. You can find all code in this Github repo basically:
- creating a bunch of threads asking for the singleton
- storing every returned object inside an Array
- checking all objects contained in that array are the same
I've found several problems (using Xcode 6.2 ergo Swift 1.1), even compiler crashes. So following this accepted SO answer I've changed your Singleton implementation avoiding the classic use of GCD. These pointers and unsafe mutable pointers you need to manage, and I was getting crashes because of that
So your Singleton class is now:
import Foundation
public class LocationManager: NSObject {
public class var sharedInstance: LocationManager {
struct Static {
static let instance: LocationManager = LocationManager()
}
return Static.instance
}
}
And to test it, you need to wait until all Threads have finished. As the test runner runs on the MainThread you need to use a expectation
describe("Accesing Location manager from multiple concurrent threads") {
context("When created") {
it("should return always the same object for every of these 500 threads") {
var allSingletons = Array<LocationManager>()
for i in 1...10 {
println("Launching thread \(i)")
dispatch_async(self.globalBackgroundQueue) {
allSingletons.append(LocationManager.sharedInstance)
}
}
expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
}
}
}
The important part is this one:
expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
Here I'm just calling a function to be sure if every stored object is the same as the passed Singleton, and giving a 10 seconds timeout
The whole Test class:
import Quick
import Nimble
import QuickNimbleExample
class LocationManagerSpec: QuickSpec {
var globalBackgroundQueue: dispatch_queue_t {
return dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)
}
func allSingletonsEqual(#inArray: Array<LocationManager>, singleton: LocationManager) -> Bool {
for loc in inArray {
if loc != singleton {
return false
}
}
return true
}
override func spec() {
describe("Accesing Location manager from multiple concurrent threads") {
context("When created") {
it("should return always the same object for every of these 500 threads") {
var allSingletons = Array<LocationManager>()
for i in 1...10 {
println("Launching thread \(i)")
dispatch_async(self.globalBackgroundQueue) {
allSingletons.append(LocationManager.sharedInstance)
}
}
expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
}
}
}
}
}