如何确保 CLLocationManager 在主线程上延迟实例化?
How can I make sure that a CLLocationManager is lazily instantiated on the main thread?
class Foo {
static let sharedInstance = Foo() // singleton
private override init() {}
lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
return manager
}()
创建了 class Foo 的单例实例,它具有延迟实例化的 CLLocationManager。 Foo 单例实例在后台线程上实例化,但必须在主线程上创建 CLLocationManager。实现该目标的最优雅方式是什么?
您可以将管理器的创建包装到在主 OperationQueue 上运行的操作中,然后等待该操作在您的初始化块中完成:
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
语句所示)。通过等待操作完成,您可以确保用于初始化惰性 属性 的管理器是 non-nil.
使用这种方法时要小心——如果您最终在主线程之外初始化位置管理器,那么如果主线程也在等待该后台工作完成,则可能会出现死锁。例如考虑:
let queue = OperationQueue()
queue.addOperation {
let _ = Foo.sharedInstance.locationManager
}
queue.waitUntilAllOperationsAreFinished()
这会尝试在后台队列上设置 locationManager
,但会阻塞主线程,直到后台工作完成。同时,后台队列试图将工作反弹到主队列以创建 CLLocationManager。由于两个队列都在等待对方,程序将逐渐停止。你需要小心避免这些情况。
class Foo {
static let sharedInstance = Foo() // singleton
private override init() {}
lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
return manager
}()
创建了 class Foo 的单例实例,它具有延迟实例化的 CLLocationManager。 Foo 单例实例在后台线程上实例化,但必须在主线程上创建 CLLocationManager。实现该目标的最优雅方式是什么?
您可以将管理器的创建包装到在主 OperationQueue 上运行的操作中,然后等待该操作在您的初始化块中完成:
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
语句所示)。通过等待操作完成,您可以确保用于初始化惰性 属性 的管理器是 non-nil.
使用这种方法时要小心——如果您最终在主线程之外初始化位置管理器,那么如果主线程也在等待该后台工作完成,则可能会出现死锁。例如考虑:
let queue = OperationQueue()
queue.addOperation {
let _ = Foo.sharedInstance.locationManager
}
queue.waitUntilAllOperationsAreFinished()
这会尝试在后台队列上设置 locationManager
,但会阻塞主线程,直到后台工作完成。同时,后台队列试图将工作反弹到主队列以创建 CLLocationManager。由于两个队列都在等待对方,程序将逐渐停止。你需要小心避免这些情况。