繁体   English   中英

如何暂停 SwiftUI 中使用的定时器?

[英]How can I pause a Timer being used in SwiftUI?

我有这个 function 改变了 map 的中心位置,这导致 map 在所有位置上进行动画处理。 纬度和经度正在递增和递减,并使用计时器重复。 但是我目前正在尝试暂停计时器。 我尝试了多种方法,似乎无法让计时器暂停几秒钟并恢复。 唯一有效的是使用睡眠,但这会导致整个 UI 暂停。 这个“移动”function 正在更新@State CLLocationCoordinate 的经纬度。 此方法称为 in.onAppear()。

timer.fire() 不起作用

我也尝试过这样的事情:

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

上面的代码不起作用

    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()
                }
                
            }
    }

下面是完整的代码:

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()
                }
                
            }
    }
}

非常感谢您的任何帮助,谢谢!

为此使用Timer并尝试使invalidate 、 re-fire 等变得困难(或者实际上是不可能的—— Timer一旦失效就无法重新触发)。 但是,这似乎是一个很好的机会,可以通过 Combine 在发布者中使用Timer ,然后给它一些时间间隔来等待——发布者仍然会触发事件,它只是在下一个等待时间间隔之前不对它们做任何事情被击中:


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
    }
}

这是发生的事情:

  1. 位置现在由 ObservableObject LocationManager 控制
  2. start()上,每 1/30 秒触发一次的发布者被触发
  3. 每次火灾时,它都会调用moveLocation()
  4. moveLocation想要暂停时,它会在发布者触发的最后一个日期之前设置waitUntil 5 秒
  5. 如果发布者被解雇并且时间在waitUntil之前,它只是返回并等待下一次触发

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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