puks1978
puks1978

Reputation: 3697

Multiple NSTimers on mapview

I have done a bit of research but couldn't find anything of value so I thought I would ask here.

I have a mapview with custom annotations. In the callouts I would like to display a count down timer. The initial countdown from time is retrieved from an api. I would like to show the countdown timer when a user taps the map annotation in the callout.

What would be the best way to manage the countdown timers consider each annotation could have a different time?

I realise there would be a performance hit having multiple timers running but at what point is too many timers on a single view controller?

Any guidance is appreciated.

Thanks

Upvotes: 2

Views: 79

Answers (1)

Code Different
Code Different

Reputation: 93191

You don't need to create multiple NSTimer. Just needs one running in the background to remind all annotation views to update the remaining time.

First the data model:

class MyAnnotation: NSObject, MKAnnotation {
    @objc var coordinate: CLLocationCoordinate2D
    @objc var title: String?
    @objc var subtitle: String?
    @objc var expirationDate: NSDate?

    init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String?, expirationDate: NSDate?) {
        self.coordinate = coordinate
        self.title = title
        self.subtitle = subtitle
        self.expirationDate = expirationDate
    }
}

And the custom Annotation View & the View Controller :

class MyAnnotationView: MKPinAnnotationView {
    static let formatter = { Void -> NSDateComponentsFormatter in
        let tmp = NSDateComponentsFormatter()
        tmp.allowedUnits = [.Minute, .Second]
        return tmp
    }()

    func updateCountDown() {
        guard let annotation = self.annotation as? MyAnnotation,
              let expirationDate = annotation.expirationDate else {
            return
        }

        annotation.subtitle = MyAnnotationView.formatter.stringFromDate(NSDate(), toDate: expirationDate)
        self.annotation = annotation
    }
}

class ViewController: UIViewController, MKMapViewDelegate {
    @IBOutlet weak var mapView: MKMapView!
    var timer: NSTimer!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.mapView.delegate = self
        addAnnotations()

        self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(ViewController.updateRemainingTime), userInfo: nil, repeats: true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func addAnnotations() {
        let coordinate1 = CLLocationCoordinate2D(latitude: 37.3316936, longitude: -122.03021910000001)
        let coordinate2 = CLLocationCoordinate2D(latitude: 37.4224187, longitude: -122.0843491)

        let appleHQ = MyAnnotation(coordinate: coordinate1, title: "Apple HQ", subtitle: "hohoho", expirationDate: NSDate(timeIntervalSinceNow: 240) )
        let googleHQ = MyAnnotation(coordinate: coordinate2, title: "Googleplex", subtitle: nil, expirationDate: NSDate(timeIntervalSinceNow: 180))

        self.mapView.addAnnotation(appleHQ)
        self.mapView.addAnnotation(googleHQ)
        self.mapView.centerCoordinate = coordinate1
        self.mapView.region.span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
    }

    func updateRemainingTime() {
        for annotation in self.mapView.annotations {
            if let view = self.mapView.viewForAnnotation(annotation) as? MyAnnotationView {
                view.updateCountDown()
            }
        }
    }

    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
        var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier("annotationView")

        if annotationView != nil {
            annotationView!.annotation = annotation
        } else {
            annotationView = MyAnnotationView(annotation: annotation, reuseIdentifier: "annotationView")
            annotationView!.canShowCallout = true
        }

        return annotationView
    }
}

Result: Count down with MapView's annotation

Upvotes: 2

Related Questions