Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove annotations from map and replace with updated annotations (qTree)

I am currently working on adding cluster annotations to my map view. Everything is working fine with the exception of a couple of things. First of all, I need to refresh the annotations on the map when the user leaves and returns to the view. At the moment this sort of works... The problem is that rather than removing the annotations and adding the new ones, the new ones are just being added in addition of the old ones so there are multiplying each time.

The next issue is that each annotation displays the distance the user is from that annotation, however the annotations are set up before the user's location is found. I assume I will just have to remove and replace the annotations once the location is found, but then I run into the issue of the annotations duplicating again.

This is my code:

override func viewDidAppear(animated: Bool) {
    println(rideArray.count)

    setUpMapView()
}

func setUpMapView() {
    rideArray = ((DataManager.sharedInstance.rideArray) as NSArray) as! [Ride]

    myLocation = mapView.userLocation.coordinate as CLLocationCoordinate2D

    zoomRegion = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2D(latitude: parkPassed.latitude!, longitude: parkPassed.longitude!), 1000, 1000)
    mapView.setRegion(zoomRegion, animated: true)
    mapView.delegate = self

    for ride in rideArray {
        println("Location: \(mapView.userLocation.coordinate.latitude)")

        var subtitle = ""
        if mapView.userLocation.location == nil {
            subtitle = "Distance unavailable"
        } else {
            let userLocation = CLLocation(latitude: mapView.userLocation.coordinate.latitude, longitude: mapView.userLocation.coordinate.longitude)
            let annotationLocation = CLLocation(latitude: ride.latitude!, longitude: ride.longitude!)

            var distance = Int(CLLocationDistance(annotationLocation.distanceFromLocation(userLocation)))

            if distance > 1000 {
                distance = distance / 1000
                subtitle = "\(distance) kilometers"
            } else {
                subtitle = "\(distance) meters"
            }
        }

        let annotation = RideAnnotation(coordinate: CLLocationCoordinate2DMake(ride.latitude!, ride.longitude!), title: ride.name!, subtitle: subtitle)
        self.qTree.insertObject(annotation)
    }

    var leftSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))
    var rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))

    leftSwipe.direction = .Left
    rightSwipe.direction = .Right

    view.addGestureRecognizer(leftSwipe)
    view.addGestureRecognizer(rightSwipe)
}

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    if annotation.isKindOfClass(QCluster.classForCoder()) {
        let PinIdentifier = "PinIdentifier"
        var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(ClusterAnnotationView.reuseId()) as? ClusterAnnotationView

        if annotationView == nil {
            annotationView = ClusterAnnotationView(cluster: annotation)
        }
        annotationView!.cluster = annotation

        return annotationView
    } else if annotation.isKindOfClass(RideAnnotation.classForCoder()) {
        var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier("RideAnnotation")

        if pinView == nil {
            pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: "RideAnnotation")
            pinView?.canShowCallout = true
            pinView?.rightCalloutAccessoryView = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as! UIButton
            pinView?.rightCalloutAccessoryView.tintColor = UIColorFromRGB(0x424242)

            let rideTimeView = UIView()
            rideTimeView.frame = CGRectMake(5, 5, 50, 50)
            rideTimeView.layer.cornerRadius = 25

            let waitTimeLabel = UILabel()
            waitTimeLabel.frame = CGRectMake(0, 0, 50, 50)
            if DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime! == "Closed" {
                waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)"
                rideTimeView.backgroundColor = getColorFromNumber(80)
                waitTimeLabel.font = UIFont(name: "Avenir", size: 15)
            } else {
                waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)m"
                rideTimeView.backgroundColor = getColorFromNumber(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!.toInt()!)
                waitTimeLabel.font = UIFont(name: "Avenir", size: 20)
            }
            waitTimeLabel.textAlignment = NSTextAlignment.Center
            waitTimeLabel.textColor = UIColor.whiteColor()
            waitTimeLabel.adjustsFontSizeToFitWidth = true
            waitTimeLabel.numberOfLines = 1

            rideTimeView.addSubview(waitTimeLabel)

            pinView.leftCalloutAccessoryView = rideTimeView
            pinView?.image = UIImage(named: "rideMapAnnotation")
        } else {
            pinView?.annotation = annotation

            let rideTimeView = UIView()
            rideTimeView.frame = CGRectMake(5, 5, 50, 50)
            rideTimeView.layer.cornerRadius = 25

            let waitTimeLabel = UILabel()
            waitTimeLabel.frame = CGRectMake(0, 0, 50, 50)
            if DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime! == "Closed" {
                waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)"
                rideTimeView.backgroundColor = getColorFromNumber(80)
                waitTimeLabel.font = UIFont(name: "Avenir", size: 15)
            } else {
                waitTimeLabel.text = "\(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!)m"
                rideTimeView.backgroundColor = getColorFromNumber(DataManager.sharedInstance.getRideByName(annotation.title!)!.waitTime!.toInt()!)
                waitTimeLabel.font = UIFont(name: "Avenir", size: 20)
            }
            waitTimeLabel.textAlignment = NSTextAlignment.Center
            waitTimeLabel.textColor = UIColor.whiteColor()
            waitTimeLabel.adjustsFontSizeToFitWidth = true
            waitTimeLabel.numberOfLines = 1

            rideTimeView.addSubview(waitTimeLabel)

            pinView.leftCalloutAccessoryView = rideTimeView
        }
        return pinView
    }
    return nil
}

func reloadAnnotations(){
    if self.isViewLoaded() == false {
        return
    }

    self.cacheArray.removeAll(keepCapacity: false)

    let mapRegion = self.mapView.region
    let minNonClusteredSpan = min(mapRegion.span.latitudeDelta, mapRegion.span.longitudeDelta) / 5
    let objects = self.qTree.getObjectsInRegion(mapRegion, minNonClusteredSpan: minNonClusteredSpan) as NSArray

    for object in objects {
        if object.isKindOfClass(QCluster){
            let c = object as? QCluster
            let neighbours = self.qTree.neighboursForLocation((c?.coordinate)!, limitCount: NSInteger((c?.objectsCount)!)) as NSArray
            for neighbour in neighbours {
                let tmp = self.rideArray.filter({
                    return $0.name == (neighbour.title)!!
                })

                if find(self.cacheArray, tmp[0]) == nil {
                    self.cacheArray.insert(tmp[0], atIndex: self.cacheArray.count)
                }
            }
        } else {
            let tmp = self.rideArray.filter({
                return $0.name == (object.title)!!
            })

            if find(self.cacheArray, tmp[0]) == nil {
                self.cacheArray.insert(tmp[0], atIndex: self.cacheArray.count)
            }
        }
    }

    let annotationsToRemove = (self.mapView.annotations as NSArray).mutableCopy() as! NSMutableArray
    annotationsToRemove.removeObject(self.mapView.userLocation)
    annotationsToRemove.removeObjectsInArray(objects as [AnyObject])
    self.mapView.removeAnnotations(annotationsToRemove as [AnyObject])
    let annotationsToAdd = objects.mutableCopy() as! NSMutableArray
    annotationsToAdd.removeObjectsInArray(self.mapView.annotations)

    self.mapView.addAnnotations(annotationsToAdd as [AnyObject])
}

func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool) {
    viewChanged = true
    self.reloadAnnotations()
}

I apologise for the extensive amount of code, but it all had to be included.

Anyone have any suggestions as to how I can remove the annotations and re-add them once the view appears?

Thanks!

EDIT:

The second issue is now resolved. Here is a bit more detail in regards to the situation and issue:

Basically each annotation represents a ride in a theme park and displays the ride name, current wait time and distance to that ride. At the moment since I am calling setUpMapView() when the view appears, all of the ride annotations are being added to the qTree each time, but are not being removed. This is the issue that I am trying to resolve, but I can't find a way to remove them from the qTree.

like image 700
user3746428 Avatar asked Jul 27 '15 19:07

user3746428


1 Answers

MKMapView has the method removeAnnotation:, which will remove a single annotation, and removeAnnotations: which will remove an array of annotations. It also has an annotations property which lets you the current array of annotations. You should be able to select and remove the annotations that you want to remove and then add new ones to replace them.

like image 111
Duncan C Avatar answered Sep 30 '22 19:09

Duncan C