Remove annotation when slider moves - swift

119 views Asked by At

i have a problem with annotations that i can't resolve. When you click on a UIButton, the @IBAction pressPlay function starts, which causes the slider on my map to start moving. The slider has the max value 0 and min -31, and the initial value is 0 and it starts to move only if the thumb is in position! = From 0 and moves every 1 second. This works correctly moves the slider.

@IBAction func pressPlay(_ sender: Any)
    {
        let calendar2 = Calendar.current
        let today = Date()
        var cnt = Int(sliderTime.value)
        let play = UIImage(named: "play")
        let pause = UIImage(named: "pause")
        let format = DateFormatter()
        playButton.setImage(play, for: .normal)
        if control == true && Int(sliderTime.value) < 0
        { //mette in play
            control = false
            playButton.setImage(pause, for: .normal)
            //removeSeismometers = true
            if Int(sliderTime.value) < 0
            {
                timer = Timer.scheduledTimer(withTimeInterval: 1,repeats: true)
                { [self]t in //ogni secondo questo timer cambia il valore dell'alpha del pin che sta vibrando
                    
                    if cnt < 0
                    {
                        cnt = Int(self.sliderTime.value)
                        self.sliderTime.value += 1
                        let newDate2 = calendar2.date(byAdding: .day, value: Int(self.sliderTime.value), to:today)! //sottraggo alla data attuale il vlaore dello slider per tornare indietro nel tempo
                        format.dateStyle = .medium // "MM/GG/AAAA"
                        self.labelTime.text = "\(format.string(from: newDate2))"
                        appo += 1
                        for i in mapEqAnnotation{
                            let str: String = i.eq.eventTime
                            let index = str.index(str.endIndex, offsetBy: -9)
                            let mySubstring = str[..<index]
                            nuovaData = calendario.date(byAdding: .day, value: Int(sliderTime.value), to:dataCorrente)!
                            let format = DateFormatter()
                            format.dateFormat = "yyyy-MM-dd"
                            let dataCntr = "\(format.string(from: nuovaData))"
                            if mySubstring == dataCntr{
                                printQuake(quake: i)
                            }else{
                                removeQuake(quake:i)
                            }
                        }
                        //printQuake(sliderValue: appo)
                    }else if cnt == 0{
                        //removeSeismometers = false
                        playButton.setImage(play, for: .normal)
                        timer!.invalidate()
                    }
                }
            }
        }else if control == false && Int(sliderTime.value) < 0 {
            playButton.setImage(play, for: .normal)
            control = true
            timer!.invalidate()
        }
    }

My problem is that every second the slider has to move when you click on the UIButton, and every second has to add an annotation to the map and remove it as soon as you move the slider again. Everything works, except that when the slider scrolls, the annotations of the previous move do not disappear, but remain on the map

    func printQuake(quake: MapEarthquakeAnnotation){
        let q = MapEarthquakeAnnotation(eq:quake.eq)
        mapView.addAnnotation(q)
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
    {
        if annotation is MapEarthquakeAnnotation{
            annotazioni.append(annotation)
            let EQAnnotation = annotation as! MapEarthquakeAnnotation
            var view: MKPinAnnotationView
            view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: EQAnnotation.identifier)
            view.canShowCallout = true
            view.pinTintColor = UIColor.brown
            return view
            
        }else if (annotation is MapSeismometerAnnotation) {
            if let annotation = annotation as? MapSeismometerAnnotation
            {
                var view: MKPinAnnotationView
                view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
                view.canShowCallout = true
                view.pinTintColor = UIColor.green
                view.image = UIImage(named: "pin-verde")
                return view
            }
            return nil
        }
        return nil
    }

Can you give me some advice?

1

There are 1 answers

0
Matic Oblak On

It would be helpful to see the code you use in removeQuake but after a quick view of your code a very likely candidate is the code

func printQuake(quake: MapEarthquakeAnnotation){
    let q = MapEarthquakeAnnotation(eq:quake.eq)
    mapView.addAnnotation(q)
}

Here you create a new annotation each time you call this method. And this annotation is not preserved anywhere. So when you call removeQuake(quake:i) you can not expect that i is any of the annotations you have added using printQuake.

I am not sure why this code was build the it was but it is possible all you need to do is change this method to

func printQuake(quake: MapEarthquakeAnnotation){
    mapView.addAnnotation(quake)
}

In general your code is a bit hard to read. You should look into more modern approaches using Swift and you should try to split parts of code so that they are easier to read and maintain. Non-English languages are not very helpful either.

I tried to tear down and reconstruct your code. Not everything is there and I am not sure it does what you want it to do. But still please inspect it. Maybe it will help you fix the issue you have.

import UIKit
import MapKit

class ViewController: UIViewController {
    
    @IBOutlet private var mapView: MKMapView!
    @IBOutlet private var sliderTime: UISlider!
    @IBOutlet private var playButton: UIButton!
    @IBOutlet private var labelTime: UILabel!

    private var timer: Timer?
    private var earthquakeAnnotations: [MapEarthquakeAnnotation] = []
    
    private var dayOffset: Int = -30 {
        didSet {
            refresh()
        }
    }
    
    private var isPlaying: Bool = false {
        didSet {
            playButton.setImage(isPlaying ? UIImage(named: "play") : UIImage(named: "pause"), for: .normal)
        }
    }
    
    private func refresh() {
        let beginningOfToday: Date = Calendar.autoupdatingCurrent.date(from: Calendar.autoupdatingCurrent.dateComponents([.year, .month, .day], from: Date()))!
        let presentedDay = Calendar.autoupdatingCurrent.date(byAdding: .day, value: dayOffset, to: beginningOfToday)!
        refreshSlider()
        refreshTimeLabel(date: presentedDay)
        refreshAnnotations(date: presentedDay)
    }
    
    private func refreshSlider() {
        sliderTime.value = Float(dayOffset)
    }
    
    private func refreshTimeLabel(date: Date) {
        labelTime.text = {
            let formatter = DateFormatter()
            formatter.dateStyle = .medium
            return formatter.string(from: date)
        }()
    }
    
    private func refreshAnnotations(date: Date) {
        earthquakeAnnotations.forEach { annotation in
            if annotation.eq.date == date {
                if !mapView.annotations.contains(where: { $0 === annotation }) {
                    mapView.addAnnotation(annotation)
                }
            } else {
                if mapView.annotations.contains(where: { $0 === annotation }) {
                    mapView.removeAnnotation(annotation)
                }
            }
        }
    }
    
    private func stopPlaying() {
        timer?.invalidate()
        timer = nil
        isPlaying = false
    }
    
    private func startPlaying() {
        if dayOffset < 0 {
            isPlaying = true
            timer?.invalidate() // Just in case
            timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { [weak self] timer in
                guard let self = self else {
                    timer.invalidate()
                    return
                }
                
                if self.dayOffset < 0 {
                    self.dayOffset += 1
                } else {
                    self.stopPlaying()
                }
            })
        } else {
            // Already at the end. Should restart?
        }
    }
    
    @IBAction func pressPausePlay(_ sender: Any) {
        if isPlaying {
            stopPlaying()
        } else {
            startPlaying()
        }
    }
    
}

// MARK: - MKMapViewDelegate

extension ViewController: MKMapViewDelegate {
    
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if let annotation = annotation as? MapEarthquakeAnnotation {
            let view: MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
            view.canShowCallout = true
            view.pinTintColor = UIColor.brown
            return view
        } else if let annotation = annotation as? MapSeismometerAnnotation {
            let view: MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
            view.canShowCallout = true
            view.pinTintColor = UIColor.green
            view.image = UIImage(named: "pin-verde")
            return view
        } else {
            return nil
        }
    }
    
}

// MARK: - MapEarthquakeAnnotation

private extension ViewController {
    
    class MapEarthquakeAnnotation: NSObject, MKAnnotation {
        var identifier: String { "MapEarthquakeAnnotationID" }
        
        let coordinate: CLLocationCoordinate2D
        let eq: Earthquake
        
        init(earthquake: Earthquake, coordinate: CLLocationCoordinate2D) { self.eq = earthquake; self.coordinate = coordinate }
    }
    
}

// MARK: - MapSeismometerAnnotation

private extension ViewController {
    
    class MapSeismometerAnnotation: NSObject, MKAnnotation {
        var identifier: String { "MapSeismometerAnnotationID" }
        
        let coordinate: CLLocationCoordinate2D
        
        init(coordinate: CLLocationCoordinate2D) { self.coordinate = coordinate }
    }
    
}

// MARK: - Earthquake

private extension ViewController {
    
    struct Earthquake {
        let eventTime: String
        
        var date: Date {
            let index = eventTime.index(eventTime.endIndex, offsetBy: -9)
            let format = DateFormatter()
            format.dateFormat = "yyyy-MM-dd"
            return format.date(from: String(eventTime[..<index])) ?? Date()
        }
    }
    
}