Я пытаюсь обновлять таймер и местоположение, пока приложение работает в фоновом режиме / телефон заблокирован.
Я пробовал несколько онлайн-решений, но пока ничего не помогло.
Мой код ниже:
class NewRunViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
let locationManager = CLLocationManager()
let regionInMeters : Double = 200
private var seconds = 0
private var timer: Timer?
private var distance = Measurement(value: 0, unit: UnitLength.meters)
private var locationList: [CLLocation] = []
var polyLine: MKPolyline = MKPolyline()
@IBOutlet weak var MapView: MKMapView!
@IBOutlet weak var DistanceLabel: UILabel!
@IBOutlet weak var PaceLabel: UILabel!
@IBOutlet weak var TimeLabel: UILabel!
@IBOutlet weak var StartButtonLabel: UIButton!
@IBOutlet weak var ResetButtonOutlet: UIButton!
@IBOutlet weak var StopPauseButtonLabel: UIButton!
@IBOutlet weak var bannerView4: GADBannerView!
@IBAction func StartButton(_ sender: UIButton) {
ResetButtonOutlet.isHidden = true
StopPauseButtonLabel.isHidden = false
StartButtonLabel.isHidden = true
updateDisplay()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
self.eachSecond()
}
startLocationUpdates()
if CLLocationManager.authorizationStatus() == .authorizedAlways {
MapView.showsUserLocation = true
}
else if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
MapView.showsUserLocation = true
}
else {
let alertController = UIAlertController(title: "Just to let you know...", message:
"Your location services are not enabled, you can still use the timer but the distance and pace won't show without your location. You can enable location services in your device settings.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
self.present(alertController, animated: true, completion: nil)
}
}
@IBAction func StopButtonLabel(_ sender: UIButton) {
StopPauseButtonLabel.isHidden = true
ResetButtonOutlet.isHidden = false
locationManager.stopUpdatingLocation()
StartButtonLabel.isHidden = false
timer?.invalidate()
}
@IBAction func ResetButton(_ sender: UIButton) {
StartButtonLabel.isHidden = false
seconds = 0
distance = Measurement(value: 0, unit: UnitLength.meters)
locationList.removeAll()
timer?.invalidate()
updateDisplay()
MapView.removeOverlays(MapView.overlays)
}
override func viewDidLoad() {
super.viewDidLoad()
checkLocationServices()
timer?.invalidate()
locationManager.stopUpdatingLocation()
StopPauseButtonLabel.titleLabel?.adjustsFontSizeToFitWidth = true
bannerView4.adUnitID = "ca-app-pub-6331942799423798/9472120281"
bannerView4.rootViewController = self
bannerView4.load(GADRequest())
MapView.delegate = self
}
func setUpLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func centreViewOnUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
MapView.setRegion(region, animated: true)
}
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setUpLocationManager()
checkLocationAuthorisation()
}
else {
let alertController = UIAlertController(title: "Just so you know...", message:
"Sadly, your location services aren't enabled, change them in your settings to track your pace and distance.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
self.present(alertController, animated: true, completion: nil)
}
}
func checkLocationAuthorisation() {
switch CLLocationManager.authorizationStatus() {
case.authorizedWhenInUse:
MapView.showsUserLocation = true
centreViewOnUserLocation()
locationManager.startUpdatingLocation()
break
case.denied:
let alertController = UIAlertController(title: "Just to let you know...", message:
"Your location services are not enabled, you can still run but without your distance and pace. If you change your mind later you can enable location services in your device settings.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
self.present(alertController, animated: true, completion: nil)
break
case.notDetermined:
locationManager.requestWhenInUseAuthorization()
break
case.restricted:
let alertController = UIAlertController(title: "Just to let you know...", message:
"Your location services are restricted, check your device settings.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
self.present(alertController, animated: true, completion: nil)
break
case.authorizedAlways:
MapView.showsUserLocation = true
centreViewOnUserLocation()
locationManager.startUpdatingLocation()
@unknown default:
break
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let centre = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion.init(center: centre, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
MapView.setRegion(region, animated: true)
for newLocation in locations {
let howRecent = newLocation.timestamp.timeIntervalSinceNow
guard newLocation.horizontalAccuracy < 20 && abs(howRecent) < 10 else { continue }
if let lastLocation = locationList.last {
let delta = newLocation.distance(from: lastLocation)
distance = distance + Measurement(value: delta, unit: UnitLength.meters)
let coordinates = [lastLocation.coordinate, newLocation.coordinate]
MapView.addOverlay(MKPolyline(coordinates: coordinates, count: 2))
let region = MKCoordinateRegion(center: newLocation.coordinate, latitudinalMeters: 200, longitudinalMeters: 200)
MapView.setRegion(region, animated: true)
}
locationList.append(newLocation)
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorisation()
}
func eachSecond() {
seconds += 1
centreViewOnUserLocation()
updateDisplay()
}
private func updateDisplay() {
let formattedDistance = FormatDisplay.distance(distance)
let formattedTime = FormatDisplay.time(seconds)
let formattedPace = FormatDisplay.pace(distance: distance,
seconds: seconds,
outputUnit: UnitSpeed.minutesPerMile)
DistanceLabel.text = "Distance: \(formattedDistance)"
TimeLabel.text = "Time: \(formattedTime)"
PaceLabel.text = "Pace: \(formattedPace)"
}
private func startLocationUpdates() {
locationManager.delegate = self
locationManager.activityType = .fitness
locationManager.distanceFilter = 10
locationManager.startUpdatingLocation()
centreViewOnUserLocation()
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
guard let polyline = overlay as? MKPolyline else {
return MKOverlayRenderer(overlay: overlay)
}
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.strokeColor = .blue
renderer.lineWidth = 3
return renderer
}
}