class Foo {
static let sharedInstance = Foo() // singleton
private override init() {}
lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
return manager
}()
创建了类Foo的单例实例,它具有延迟实例化的CLLocationManager。 Foo单例实例在后台线程上实例化,但必须在主线程上创建CLLocationManager。实现这一目标最优雅的方式是什么?
答案 0 :(得分:1)
您可以将管理器的创建包装到在主OperationQueue上运行的Operation中,然后等待该操作在初始化块内完成:
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
}()
}
通过将此操作放在主队列上,可以确保在主线程上设置管理器(由print
语句证明)。通过等待操作完成,您可以确保用于初始化惰性属性的管理器是非零的。
小心这种方法 - 如果你最终关闭主线程初始化位置管理器,如果主线程也在等待后台工作完成,它可能会死锁。例如,考虑一下:
let queue = OperationQueue()
queue.addOperation {
let _ = Foo.sharedInstance.locationManager
}
queue.waitUntilAllOperationsAreFinished()
这会尝试在后台队列上设置locationManager
,但会阻止主线程直到后台工作完成。同时,后台队列正在尝试将工作弹回到主队列以创建CLLocationManager。由于两个队列都在相互等待,程序将停止运行。你需要小心避免这种情况。