Swift 在应用程序关闭和重新打开时更新UI时节省时间的问题。敏捷的

Swift 在应用程序关闭和重新打开时更新UI时节省时间的问题。敏捷的,swift,nsuserdefaults,Swift,Nsuserdefaults,我试图在应用程序关闭然后重新打开时更新计时器,我知道这是一种节省关闭时间的情况,然后计算关闭和打开时间之间的差值,然后将其添加到关闭前的时间计数中,我已经实现了上面的代码,在世界上所有的评论中,我似乎都无法解决这个问题 任何帮助都将不胜感激 我已经回顾了其他类似的问题,但到目前为止还没有找到解决方案,从我的代码中我看不出哪里出了问题 再次感谢 乔希 导入UIKit 导入地图套件 导入核心定位 进口谷歌手机 导入用户通知 类NewRunViewController:UIViewController

我试图在应用程序关闭然后重新打开时更新计时器,我知道这是一种节省关闭时间的情况,然后计算关闭和打开时间之间的差值,然后将其添加到关闭前的时间计数中,我已经实现了上面的代码,在世界上所有的评论中,我似乎都无法解决这个问题

任何帮助都将不胜感激

我已经回顾了其他类似的问题,但到目前为止还没有找到解决方案,从我的代码中我看不出哪里出了问题

再次感谢

乔希

导入UIKit 导入地图套件 导入核心定位 进口谷歌手机 导入用户通知

类NewRunViewController:UIViewController、CLLocationManagerDelegate、MKMapViewDelegate{

let locationManager = CLLocationManager()
let regionInMeters : Double = 200
var seconds = 0
private var timer: Timer?
private var distance = Measurement(value: 0, unit: UnitLength.meters)
private var locationList: [CLLocation] = []
var polyLine: MKPolyline = MKPolyline()
var isCounting : Bool = false

@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) {
    
    isCounting = true
    ResetButtonOutlet.isHidden = true
    StopPauseButtonLabel.isHidden = false
    StartButtonLabel.isHidden = true
    updateDisplay(secondsForTime: seconds)
    startLocationUpdates()
    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
      self.eachSecond()
    }
    

    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) {
    
    isCounting = false
    StopPauseButtonLabel.isHidden = true
    ResetButtonOutlet.isHidden = false
    locationManager.stopUpdatingLocation()
    StartButtonLabel.isHidden = false
    timer?.invalidate()
}


@IBAction func ResetButton(_ sender: UIButton) {
    
    isCounting = false
    StartButtonLabel.isHidden = false
    seconds = 0
    distance = Measurement(value: 0, unit: UnitLength.meters)
    locationList.removeAll()
    timer?.invalidate()
    updateDisplay(secondsForTime: seconds)
    MapView.removeOverlays(MapView.overlays)
    UserDefaults.standard.removeObject(forKey: "savedTime")
    UserDefaults.standard.removeObject(forKey: "timeClosed")
}

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
    
    NotificationCenter.default.addObserver(self, selector: #selector(pauseWhenInBackground(noti:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
    
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(noti:)), name: UIApplication.didBecomeActiveNotification, object: nil)
//NotificationCenter.default.addObserver(self,选择器:#选择器(pauseWhenInBackground(noti:)),名称:UIApplication.didEnterBackgroundNotification,对象:nil) }

func setUpLocationManager(){
locationManager.delegate=self
locationManager.desiredAccuracy=KCallocationAccuracyBest
}
func centreViewOnUserLocation(){
如果let location=locationManager.location?坐标{
设region=MKCoordinateRegion.init(中心:位置,纬度:区域,经度:区域)
MapView.setRegion(区域,动画:true)
}
}
func checkLocationServices(){
如果CLLocationManager.locationServicesEnabled(){
setUpLocationManager()
checkLocationAuthorization()
}
否则{
让alertController=UIAlertController(标题:“让您知道…”),消息:
“很遗憾,您的位置服务未启用,请在您的设置中更改它们以跟踪您的速度和距离。”,preferredStyle:。警报)
addAction(UIAlertAction(标题:“解除”,样式:。默认值))
self.present(alertController,动画:true,完成:nil)
}
}
func openSettings(警报:UIAlertAction!){
如果let url=url.init(字符串:UIApplication.opensetingsurlstring){
UIApplication.shared.open(url,选项:[:],completionHandler:nil)
}
}
职能检查位置授权(){
开关CLLocationManager.authorizationStatus(){
case.dwheninuse:
MapView.showsUserLocation=true
中心位置()
locationManager.startUpdatingLocation()
let alertController=UIAlertController(标题:“只想让您知道…”),消息:
“如果要在运行时关闭应用程序或锁定手机,请转到“设备设置”并启用“始终”位置”,preferredStyle:。警报)
addAction(UIAlertAction(标题:“解除”,样式:。默认值))
alertController.addAction(UIAlertAction)(标题:“打开设置”,
样式:UIAlertAction.style.default,
处理程序:openSettings)
self.present(alertController,动画:true,完成:nil)
打破
案例1被驳回:
let alertController=UIAlertController(标题:“只想让您知道…”),消息:
“您的位置服务未启用,您仍可以跑步,但不需要距离和配速。如果您以后改变主意,您可以在设备设置中启用位置服务。”,preferredStyle:。警报)
addAction(UIAlertAction(标题:“解除”,样式:。默认值))
self.present(alertController,动画:true,完成:nil)
打破
未确定的案例:
locationManager.RequestWhenUseAuthorization()
打破
限制性案例:
let alertController=UIAlertController(标题:“只想让您知道…”),消息:
“您的位置服务受到限制,请检查您的设备设置。”,preferredStyle:。警报)
addAction(UIAlertAction(标题:“解除”,样式:。默认值))
self.present(alertController,动画:true,完成:nil)
打破
case.Ways:
MapView.showsUserLocation=true
中心位置()
locationManager.startUpdatingLocation()
@未知默认值:
打破
}
}
func locationManager(manager:CLLocationManager,didUpdateLocations位置:[CLLocation]){
guard let location=locations.last else{return}
设中心=CLLocationCoordinate2D(纬度:location.coordinate.lation,经度:location.coordinate.longitude)
设region=MKCoordinateRegion.init(中心:中心,纬度:区域,经度:区域)
MapView.setRegion(区域,动画:true)
对于位置中的新位置{
让howRecent=newLocation.timestamp.timeIntervalSinceNow
guard newLocation.horizontalAccuracy<20&&abs(最近几次)<10 else{continue}
如果let lastLocation=locationList.last{
设delta=newLocation.distance(from:lastLocation)
距离=距离+测量值(值:增量,单位:UnitLength.m)
让坐标=[lastLocation.coordinate,newLocation.coordinate]
MapView.addOverlay(MKPolyline(坐标:坐标,计数:2))
let region=MKCoordinateRegion(中心:newLocation.coordinate,纬度计:200,纵向计:200)
MapView.setRegion(区域,动画:true)
}
locationList.append(新位置)
}
}
func locationManager(\ manager:CLLocationManager,didChangeAuthorization状态:CLAuthorizationStatus){
checkLocationAuthorization()
}
func eachSecond(){
秒+=1
中心位置()
updateDisplay(秒时间:秒)
}
@objc private func updateDisplay(secondsForTime:Int){
让formattedDistance=FormattDisplay.distance(距离)
让我们形成
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 openSettings(alert: UIAlertAction!) {
    if let url = URL.init(string: UIApplication.openSettingsURLString) {
        UIApplication.shared.open(url, options: [:], completionHandler: nil)
    }
}

func checkLocationAuthorisation() {
    switch CLLocationManager.authorizationStatus() {
        
    case.authorizedWhenInUse:
        
        MapView.showsUserLocation = true
        centreViewOnUserLocation()
        locationManager.startUpdatingLocation()
        let alertController = UIAlertController(title: "Just to let you know...", message:
            "If you want to close the app or lock your phone while running, please go to device settings and enable 'Always' location", preferredStyle: .alert)
        
        alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))

        alertController.addAction(UIAlertAction(title: "Open Settings",
                                      style: UIAlertAction.Style.default,
                                      handler: openSettings))
        self.present(alertController, animated: true, completion: nil)
        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(secondsForTime : seconds)
}

@objc private func updateDisplay(secondsForTime : Int) {
  let formattedDistance = FormatDisplay.distance(distance)
  let formattedTime = FormatDisplay.time(secondsForTime)
  let formattedPace = FormatDisplay.pace(distance: distance,
                                         seconds: secondsForTime,
                                         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
}

@objc func pauseWhenInBackground(noti : Notification){
    
    if seconds == 0 {
        
    }
    
    else {
        
        UserDefaults.standard.removeObject(forKey: "savedTime")
        UserDefaults.standard.removeObject(forKey: "timeClosed")
        let shared = UserDefaults.standard
        shared.set(seconds, forKey: "savedTime")
        print(seconds)
        let timeClosed = Date()
        shared.set(timeClosed, forKey: "timeClosed")
        shared.set(isCounting, forKey: "isCounting")
        print(timeClosed)
        timer?.invalidate()
        updateDisplay(secondsForTime: 0)
    }
}

@objc func willEnterForeground(noti : Notification) {
    
    let isStillCounting = UserDefaults.standard.bool(forKey: "isCounting")
    
    print(isStillCounting)
    
    if isStillCounting == true {

    if let savedDate = (UserDefaults.standard.object(forKey: "timeClosed") as? Date){
        print(savedDate)
        
    getTimeDiffernce(startDate: savedDate)
        
        timer?.invalidate()
        
    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)
     }
    }
    else {}
 }
}

func getTimeDiffernce(startDate : Date) {
    let calender = Calendar.current
    let components = calender.dateComponents([.hour, .minute, .second], from: startDate, to: Date())
    let diffHours = components.hour!
    let diffMins = components.minute!
    let diffSecs = components.second!
    let secsFromHours = diffHours % 3600
    let secsFromMins = diffMins % 60
    let savedSeconds = UserDefaults.standard.integer(forKey: "savedTime")
    seconds = secsFromHours + secsFromMins + diffSecs + savedSeconds
    print(seconds)
    updateDisplay(secondsForTime: seconds)
}