Reputation: 228
class Foo {
static let sharedInstance = Foo() // singleton
private override init() {}
lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
return manager
}()
A singleton instance of class Foo is created which has a lazily instantiated CLLocationManager. The Foo singleton instance is instantiated on a background thread, but a CLLocationManager must be created on the main thread. What is the most elegant way of achieving that?
Upvotes: 3
Views: 662
Reputation: 60150
You can wrap up the creation of the manager into an Operation that runs on the main OperationQueue, then wait for that operation to finish inside your initialization block:
class Foo {
static let sharedInstance = Foo()
private init() {}
lazy var locationManager: CLLocationManager = {
var manager: CLLocationManager!
let op = BlockOperation {
print("Main thread: \(Thread.isMainThread ? "YES" : "NO")")
manager = CLLocationManager()
}
OperationQueue.main.addOperation(op)
op.waitUntilFinished()
return manager
}()
}
By placing this operation on the main queue, you ensure that setting up the manager happens on the main thread (as evidenced by the print
statement). By waiting for the operation to finish, you ensure that the manager used to initialize the lazy property is non-nil.
Be careful with this approach — if you do wind up initializing the location manager off the main thread, it's possible to deadlock if the main thread is also waiting on that background work to complete. Consider, for example:
let queue = OperationQueue()
queue.addOperation {
let _ = Foo.sharedInstance.locationManager
}
queue.waitUntilAllOperationsAreFinished()
This tries to set up the locationManager
on a background queue, but blocks the main thread until that background work is done. At the same time, the background queue is attempting to bounce work to the main queue to create the CLLocationManager. Since both queues are waiting on each other, the program will grind to a halt. You'll need to be careful to avoid these kinds of situations.
Upvotes: 3