简体   繁体   中英

How can I pause a Timer being used in SwiftUI?

I have this function that changes the centerLocation of the map, this causes the map to animate over all the locations. The lat and longitude are being incremented and decremented and repeats with the use of a timer. However I am currently trying to pause the timer. I have tried multiple methods and can't seem to get the timer to pause for a few seconds and resume. The only thing that works is using sleep, but that causes the whole UI to pause. This 'move' function is updating an @State CLLocationCoordinate's lat and long. This method is called in.onAppear().

timer.fire() does not work

I also tried something like this:

        timer.invalidate()
         DispatchQueue.main.asyncAfter(deadline: .now() + 5.00) {
          
            timer.fire()
        }

Code above does not work

    func moveRegion() {
        
            var currentLatitude = region.center.latitude
            var currentLongitude = region.center.longitude
        
            let increment = 0.25
            var southAmerica = false
            var europe = false
            var australia = false
            var america = true
        
            Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
                //AMERICA CORD 37.0000, -95.000
                //MOVING TO SOUTH AMERICA
                //SOUTH AMERICA CORD -33.000, -70.000
                if (america == true && southAmerica == false && europe == false && australia == false){
                    if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
                        currentLatitude -= increment
                        currentLatitude -= increment
                        currentLatitude -= increment
                        if currentLongitude < -70.00 {
                            currentLongitude += increment
                        }
                    }
                    if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006  && currentLongitude <=  -69.95000000000142){
                       // sleep(5), works but pauses whole UI
                        timer.invalidate()
                        Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { pauseTimer in
                            timer.fire()
                            print(timer.isValid)
                        }
                      
                        southAmerica = true
                        australia = false
                        america = false
                        europe = false
                    }
                }
                //MOVING TO EUROPE
                //Europe CORD 48.000, 15.000
                //if (currentLongitude > -74.00 && currentLongitude < -4.00)
                    if (southAmerica == true && australia == false && america == false && europe == false ){
                        if (currentLatitude > -39.000 && currentLatitude <  55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                        if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
                            
                            sleep(5)
                            
                            europe = true
                            southAmerica = false
                            australia = false
                            america = false
                        }
                    }
                    //MOVING TO AUSTRALIA
                    //AUSTRALIA CORD -36.000, 133.000
                    if (europe == true && southAmerica == false && australia == false && america == false){
                        if (currentLongitude > 9.00 && currentLongitude < 133.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
                            currentLatitude -= increment
                            currentLatitude -= increment
                        }
                    if (currentLatitude <= -37.05000000000008  && currentLongitude >= 132.04999999999274){
                        sleep(5)
                        australia = true
                        southAmerica = false
                        europe = false
                        america = false
                    }
                }
                    //MOVING TO AMERIA
                    if (australia == true && southAmerica == false && america == false && europe == false){
                        if (currentLongitude < 179.55){
                            currentLongitude += increment
                            currentLongitude += increment
                            if (currentLongitude > 179.500){
                                currentLongitude = -179.000
                              }
                        }
                        if (currentLongitude > -95.100) {
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                    if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
                        australia = false
                        southAmerica = false
                        europe = false
                        america = true
                        currentLatitude = 37.0000
                        currentLongitude = -95.000
                        sleep(5)
                    }
                }
                region.center.longitude = currentLongitude
                region.center.latitude = currentLatitude
                centerLocation.latitude = currentLatitude
                centerLocation.longitude = currentLongitude
               }
        
    }

Then in the view

            var body: some View {

        SwiftUIMapView(centerLocation: $centerLocation)
            .onAppear {
                DispatchQueue.main.async {
                  moveRegion()
                }
                
            }
    }

Here is the full code bellow:

import SwiftUI
import MapKit

struct MapView: View {

    var timer = Timer()
    //Start Location of the Map
    @State var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.0000, longitude: -95.000),
        span: MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
    )
    
    @State var centerLocation = CLLocationCoordinate2D()
   

    func moveRegion() {
        
            var currentLatitude = region.center.latitude
            var currentLongitude = region.center.longitude
        
            let increment = 0.25
            var southAmerica = false
            var europe = false
            var australia = false
            var america = true
        
            Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
                //AMERICA CORD 37.0000, -95.000
                //MOVING TO SOUTH AMERICA
                //SOUTH AMERICA CORD -33.000, -70.000
                if (america == true && southAmerica == false && europe == false && australia == false){
                    if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
                        currentLatitude -= increment
                        currentLatitude -= increment
                        currentLatitude -= increment
                        if currentLongitude < -70.00 {
                            currentLongitude += increment
                        }
                    }
                    if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006  && currentLongitude <=  -69.95000000000142){
                       // sleep(5), works but pauses whole UI
                        timer.invalidate()
                        Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { pauseTimer in
                            timer.fire()
                            print(timer.isValid)
                        }
                      
                        southAmerica = true
                        australia = false
                        america = false
                        europe = false
                    }
                }
                //MOVING TO EUROPE
                //Europe CORD 48.000, 15.000
                //if (currentLongitude > -74.00 && currentLongitude < -4.00)
                    if (southAmerica == true && australia == false && america == false && europe == false ){
                        if (currentLatitude > -39.000 && currentLatitude <  55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                        if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
                            
                            sleep(5)
                            
                            europe = true
                            southAmerica = false
                            australia = false
                            america = false
                        }
                    }
                    //MOVING TO AUSTRALIA
                    //AUSTRALIA CORD -36.000, 133.000
                    if (europe == true && southAmerica == false && australia == false && america == false){
                        if (currentLongitude > 9.00 && currentLongitude < 133.000) {
                            currentLongitude += increment
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
                            currentLatitude -= increment
                            currentLatitude -= increment
                        }
                    if (currentLatitude <= -37.05000000000008  && currentLongitude >= 132.04999999999274){
                        sleep(5)
                        australia = true
                        southAmerica = false
                        europe = false
                        america = false
                    }
                }
                    //MOVING TO AMERIA
                    if (australia == true && southAmerica == false && america == false && europe == false){
                        if (currentLongitude < 179.55){
                            currentLongitude += increment
                            currentLongitude += increment
                            if (currentLongitude > 179.500){
                                currentLongitude = -179.000
                              }
                        }
                        if (currentLongitude > -95.100) {
                            currentLongitude += increment
                            currentLongitude += increment
                        }
                        if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
                            currentLatitude += increment
                            currentLatitude += increment
                        }
                    if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
                        australia = false
                        southAmerica = false
                        europe = false
                        america = true
                        currentLatitude = 37.0000
                        currentLongitude = -95.000
                        sleep(5)
                    }
                }
                region.center.longitude = currentLongitude
                region.center.latitude = currentLatitude
                centerLocation.latitude = currentLatitude
                centerLocation.longitude = currentLongitude
               }
        
    }

    var body: some View {

        SwiftUIMapView(centerLocation: $centerLocation)
            .onAppear {
                DispatchQueue.main.async {
                  moveRegion()
                }
                
            }
    }
}

Any help is greatly appreciated thank you!

Using Timer for this and trying to invalidate , re-fire, etc is going to be difficult (or in fact, impossible -- Timer can't re-fire once it is invalidated). But, this seemed like a pretty good opportunity to user Timer in a publisher with Combine and then just give it some intervals to wait out -- the publisher still fires events, it just doesn't do anything with them until the next wait interval has been hit:


struct ContentView : View {
    var body: some View {
        MapView()
    }
}

class LocationManager : ObservableObject {
    @Published var centerLocation = CLLocationCoordinate2D()
    @Published var region : MKCoordinateRegion
    
    private var currentLatitude : CLLocationDegrees
    private var currentLongitude : CLLocationDegrees
    
    init() {
        let region = MKCoordinateRegion(
            center: CLLocationCoordinate2D(latitude: 37.0000, longitude: -95.000),
            span: MKCoordinateSpan(latitudeDelta: 40, longitudeDelta: 40)
        )
        currentLatitude = region.center.latitude
        currentLongitude = region.center.longitude
        self.region = region
    }
    
    private var cancellable : AnyCancellable?
    
    private var waitUntil : Date?
    private var currentFireDate : Date = Date()
    
    func start() {
        cancellable = Timer.publish(every: (1.0/30.0), on: .main, in: .default)
            .autoconnect()
            .sink { val in
                if let waitUntil = self.waitUntil {
                    if val < waitUntil {
                        return
                    } else {
                        self.waitUntil = nil
                    }
                }
                self.currentFireDate = val
                self.moveRegion()
            }
    }
    
    let increment = 0.25
    var southAmerica = false
    var europe = false
    var australia = false
    var america = true
    
    func moveRegion() {
        //AMERICA CORD 37.0000, -95.000
        //MOVING TO SOUTH AMERICA
        //SOUTH AMERICA CORD -33.000, -70.000
        if (america == true && southAmerica == false && europe == false && australia == false){
            if (currentLatitude <= -33.000 && currentLatitude >= 37.0000 || currentLongitude <= -70.0000 && currentLongitude >= -95.0000 || currentLongitude >= -101.69999999998991) {
                currentLatitude -= increment
                currentLatitude -= increment
                currentLatitude -= increment
                if currentLongitude < -70.00 {
                    currentLongitude += increment
                }
            }
            if (currentLatitude == -38.15000000000002 || currentLatitude <= -38.150000000000006  && currentLongitude <=  -69.95000000000142){
                waitUntil = currentFireDate.addingTimeInterval(5.0)
                
                southAmerica = true
                australia = false
                america = false
                europe = false
            }
        }
        //MOVING TO EUROPE
        //Europe CORD 48.000, 15.000
        //if (currentLongitude > -74.00 && currentLongitude < -4.00)
        if (southAmerica == true && australia == false && america == false && europe == false ){
            if (currentLatitude > -39.000 && currentLatitude <  55.000 || currentLongitude > -70.00 && currentLongitude < 16.000) {
                currentLongitude += increment
                currentLongitude += increment
                currentLatitude += increment
                currentLatitude += increment
            }
            if (currentLatitude >= 48.04999999999936 || currentLatitude == 48.04999999999937 && currentLongitude <= 16.249999999996835){
                
                waitUntil = currentFireDate.addingTimeInterval(5.0)
                
                europe = true
                southAmerica = false
                australia = false
                america = false
            }
        }
        //MOVING TO AUSTRALIA
        //AUSTRALIA CORD -36.000, 133.000
        if (europe == true && southAmerica == false && australia == false && america == false){
            if (currentLongitude > 9.00 && currentLongitude < 133.000) {
                currentLongitude += increment
                currentLongitude += increment
                currentLongitude += increment
            }
            if (currentLatitude >= -38.000 && currentLatitude <= 49.0000){
                currentLatitude -= increment
                currentLatitude -= increment
            }
            if (currentLatitude <= -37.05000000000008  && currentLongitude >= 132.04999999999274){
                waitUntil = currentFireDate.addingTimeInterval(5.0)
                australia = true
                southAmerica = false
                europe = false
                america = false
            }
        }
        //MOVING TO AMERIA
        if (australia == true && southAmerica == false && america == false && europe == false){
            if (currentLongitude < 179.55){
                currentLongitude += increment
                currentLongitude += increment
                if (currentLongitude > 179.500){
                    currentLongitude = -179.000
                }
            }
            if (currentLongitude > -95.100) {
                currentLongitude += increment
                currentLongitude += increment
            }
            if (currentLatitude >= -39.000 && currentLatitude <= 37.0000){
                currentLatitude += increment
                currentLatitude += increment
            }
            if (currentLatitude >= 37.04999999999998 && currentLongitude >= -95.100){
                australia = false
                southAmerica = false
                europe = false
                america = true
                currentLatitude = 37.0000
                currentLongitude = -95.000
                waitUntil = currentFireDate.addingTimeInterval(5.0)
            }
        }
        region.center.longitude = currentLongitude
        region.center.latitude = currentLatitude
        centerLocation.latitude = currentLatitude
        centerLocation.longitude = currentLongitude
    }
}

struct MapView: View {
    @ObservedObject var locationManager = LocationManager()
    var body: some View {
        
        SwiftUIMapView(centerLocation: $locationManager.centerLocation)
            .onAppear {
                locationManager.start()
            }
    }
}

struct SwiftUIMapView : UIViewRepresentable {
    @Binding var centerLocation : CLLocationCoordinate2D

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        return mapView
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        uiView.centerCoordinate = centerLocation
    }
}

Here's what happens:

  1. Location is now controlled by an ObservableObject LocationManager
  2. On start() , a publisher that fires once every 1/30 seconds is fired
  3. On each fire, it calls moveLocation()
  4. When moveLocation wants to pause, it sets waitUntil 5 seconds ahead of the last date of the publisher firing
  5. If the the publisher gets fired and the time is before waitUntil , it just returns and waits for the next fire

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM