Necesito ubicación precisa. Para lograr el objetivo, he usado la siguiente lógica:
Entonces, en mi código, el temporizador se iniciará/detendrá dentro del método didUpdateLocations varias veces.
Pero se bloquea al azar. Aquí está la información del accidente:
libc++abi: terminating with uncaught exception of type std::bad_alloc: std::bad_alloc dyld4 config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/usr/lib/libMTLCapture.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib terminating with uncaught exception of type std::bad_alloc: std::bad_allocAquí está mi código completo:
import UIKit import CoreLocation final class MapView: UIView { private lazy var locationImprover = TimerBasedLocationImprover(acceptInitialLocation: true) {[weak self] location in self?.updatedLocation(location) } private lazy var locationManager = CLLocationManager() init() { super.init(frame: .zero) setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { stopUpdating() } private func setup() { setupLocationManager() } private func setupLocationManager() { locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation locationManager.distanceFilter = 1 locationManager.delegate = self locationManager.requestWhenInUseAuthorization() startUpdating(manager: locationManager) } private func startUpdating(manager: CLLocationManager) { if CLLocationManager.locationServicesEnabled() { manager.startUpdatingLocation() } if CLLocationManager.headingAvailable() { manager.startUpdatingHeading() } } func stopUpdating() { locationManager.stopUpdatingLocation() locationManager.stopUpdatingHeading() } private func updatedLocation(_ location: CLLocation) { //Some UI update } } extension MapView: CLLocationManagerDelegate { func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { startUpdating(manager: manager) } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { startUpdating(manager: manager) } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let lastLocation = locations.last, let improvedLocation = locationImprover.improved(location: lastLocation) else { return } updatedLocation(improvedLocation) } func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) { guard newHeading.headingAccuracy > 0 else { return } } } final class TimerBasedLocationImprover { private var _lastLocation: CLLocation? private let lastLocationLock = NSLock() private var lastLocation: CLLocation? { get { defer { lastLocationLock.unlock() } lastLocationLock.lock() return _lastLocation } set { lastLocationLock.lock() _lastLocation = newValue lastLocationLock.unlock() } } private var _workItem: DispatchWorkItem? private let workItemLock = NSLock() private var workItem: DispatchWorkItem? { get { defer { workItemLock.unlock() } workItemLock.lock() return _workItem } set { workItemLock.lock() _workItem = newValue workItemLock.unlock() } } private let timerThreashold: TimeInterval private let acceptInitialLocation: Bool private let onReachThreashold: (CLLocation) -> Void init(timerThreashold: TimeInterval = 5, acceptInitialLocation: Bool, onReachThreashold: @escaping (CLLocation) -> Void) { self.timerThreashold = timerThreashold self.acceptInitialLocation = acceptInitialLocation self.onReachThreashold = onReachThreashold startTimer() } deinit { stopTimer() } func improved(location: CLLocation) -> CLLocation? { debugPrint("improved thread is main: \(Thread.isMainThread)") if lastLocation == nil, acceptInitialLocation { startTimer() lastLocation = location startTimer() return location } lastLocation = location guard location.isAccurate else { return nil } startTimer() return location } private func startTimer() { debugPrint("startTimer thread is main: \(Thread.isMainThread)") stopTimer() let wi = DispatchWorkItem() {[weak self] in self?.timerDone() } DispatchQueue.global(qos: .background) .asyncAfter(deadline: .now() + timerThreashold, execute: wi) workItem = wi } private func stopTimer() { workItem?.cancel() workItem = nil } private func timerDone() { if let lastLocation = lastLocation { DispatchQueue.main.async { self.onReachThreashold(lastLocation) } } startTimer() } } extension CLLocation { var isAccurate: Bool { horizontalAccuracy > 0 && horizontalAccuracy > 20 } }