Currently working with Map Views and adding pins to the map. I know how to add a single point to the map using addAnotation() method. Now, I am trying to add multiple points to the MapView in the easiest way. I've fetched the data (latitude, longitude and name from an online XML file) and stored it in an array and now I want to add all those coordinates+name as pins in the map. For doing so I've declared an array of MKPointAnnotation objects like so:
var pinsArray: [MKPointAnnotation] = []
And then for dumping the collected data to I've done the following:
for i in 0...(myFeed.count-1) {
pinsArray[i].title = myFeed.objectAtIndex(i).objectForKey("NOMBRE")!.stringValue
pinsArray[i].coordinate = CLLocationCoordinate2D(latitude: myFeed[i].objectForKey("LATITUD")!.doubleValue, longitude: myFeed[i].objectForKey("LONGITUD")!.doubleValue)
pinsArray[i].subtitle = ""
mapView.addAnnotation(pinsArray[i])
}
But when I run the app I get an error saying that the array index is out of range (fatal error: Array index out of range). I guess this is a problem on the declaration of the pinsArray, I do not really know how to solve this one.
Try this:
var pinsArray: [MKPointAnnotation] = []
for i in 0...(myFeed.count-1)
{
let pointAnnotation = MKPointAnnotation() // First create an annotation.
pointAnnotation.title = myFeed.objectAtIndex(i).objectForKey("NOMBRE")!.stringValue
pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: myFeed[i].objectForKey("LATITUD")!.doubleValue, longitude: myFeed[i].objectForKey("LONGITUD")!.doubleValue)
pointAnnotation.subtitle = ""
pinsArray.append(pointAnnotation) // Now append this newly created annotation to array.
}
mapView.addAnnotations(pinsArray) // Add all the annotations to map view at once.
Related
I'm attempting to return the value of an array and then assign its value to a variable, however when doing so, it returns a blank array. I'm assuming this is due to my lack of knowledge on how to use async in swift so was hoping someone could show me how to do so for this segment of code:
func assignWeights(){
var weightedList = [GMUWeightedLatLng]()
getCoords { coords in
self.coords = coords
for coord in coords {
let lat = Double(coords.location.latitude)!
let long = Double(coords.location.longitude)!
let coordinates = GMUWeightedLatLng(coordinate: CLLocationCoordinate2DMake(lat,long), intensity: 2.0)
weightedList.append(coordinates)
}
print(weightedList) //Array prints contents
}
print(weightedList) //Empty array
heatmapLayer.weightedData = weightedList //Sets to empty array [] as this is ran before getCoords{
}
I feel like this is something simple that I am just over looking. I have a map that the user pushes a button to add an annotation.
func addPinToPath() {
let catchPathPin = CatchAnnotation()
let catchLat = map.userLocation.coordinate.latitude
let catchLon = map.userLocation.coordinate.longitude
catchPathPin.coordinate = CLLocationCoordinate2D(latitude: catchLat, longitude: catchLon)
catchPathPin.title = "Fish On"
catchPathPin.subtitle = "Path"
catchPathPin.annoID = annoIDStart
catchPathPin.pinImageName = "catch"
let idToPass = catchPathPin.annoID
annoIDCatch = idToPass!
print(annoIDCatch)
map.addAnnotation(catchPathPin)
bitesInRoute = catchPathPin
}
at this point I would like to have a counter that shows in the display as to how many annotations are added.
annotations.count will give me a count of all annotations, but I only want the count for CatchPathPin
Theres two options. You could have a count variable that you increment every time
addPinToPath is called. The other option is to filter the current annotations and get the count from there.
count = map.annotations
.filter { $0 is CatchAnnotation }
.count
I'm working on a tvOS app, where I want to be able to swipe between annotations. I store my annotations in a Dictionary, and store the Dictionary in an Array for future use. I am simply plotting three annotations for Canada, USA, and Mexico. I want to be able to swipe on the remote between these annotations. When an annotation is clicked, it will take you to information about that country.
let countriesArray = ["Canada", "Mexico", "United States of America"]
var annotationArray = [MKPointAnnotation]()
var locationDictionary = [String: AnyObject]()
var locationArray = [AnyObject]()
Once the three countries are plotted, my array looks like the following:
locationArray [{
annotation = "<MKPointAnnotation: 0x7fc021b01f70>";
country = Canada;
latitude = "71.47385399229037";
longitude = "-96.81064609999999";
}, {
annotation = "<MKPointAnnotation: 0x7fc0219dcf90>";
country = "United States of America";
latitude = "37.99472997055178";
longitude = "-95.85629150000001";
}, {
annotation = "<MKPointAnnotation: 0x7fc02260ff70>";
country = Mexico;
latitude = "23.94480686844645";
longitude = "-102.55803745";
}]
When the Apple remote is swipped, down, for example, I'm getting the following error on the if condition below.
Binary operator '==' cannot be applied to operands of type '[MKAnnotation]' and 'MKAnnotation'
How can I compare the annotation in the arrary to the one selected?
func swipedDown(sender:UISwipeGestureRecognizer) {
print("Down")
let selectedAnnotation = mapView.selectedAnnotations
for x in 0 ... locationArray.count - 1 {
let value = locationArray[x].valueForKey("annotation") as! MKAnnotation
if selectedAnnotation == value { //error
let currentLocation = locationArray[x].valueForKey("country")
print("Your on \(currentLocation)")
}
}
}
Since mapView.selectedAnnotations returns an array of MKAnnotations, i.e. an [MKAnnotation], comparing it to a single MKAnnotation value with operator == does not work. You need to decide what to do with multiple values from the array - specifically, whether the comparison should be true when any of the annotations in the array matches value, or when the first one matches value, or all of them match value.
If you need to check that one array element matches the value, you can use contains, like this:
if (selectedAnnotation.contains { $0.title == value.title && $0.subtitle == value.subtitle }) {
let currentLocation = locationArray[x].valueForKey("country")
print("Your on \(currentLocation)")
}
Edit: The initial attempt at using non-closure contains has failed, because MKAnnotation does not conform to Equatable protocol. Thanks, dan, for catching this!
1- [MKAnnotation] is an array of MKAnnotation , can you notice the difference?
2- let selectedAnnotation = mapView.selectedAnnotations here, you are storing all the annotations not the current one, can you notice the s in this statement mapView.selectedAnnotations ?
I have a method that showing me multiple Annotations on the map. Its About 10 000 annotation so i have to show only annotation that are visible on the map in current time. When I move with map i execute method that return me objects with coordinates that will be visible. But my method will delete all of them and start to adding them to map one by one. My goal is when I present Annotations and i move with map i want to keep the ones that are visible and the others remove. I am using this and FBAnnotationClusteringSwift framework.
this is my method for adding pins.
private var arrOfPinsOnMap:[FBAnnotation] = []
private var clusteringManager = FBClusteringManager()
func addMapPoints(){
self.arrOfPinsOnMap.removeAll()
self.clusteringManager = FBClusteringManager() //everytime recreate instance otherwise there will be duplicates.
for i in 0..<sortedObjectsByDistance_ids.count {
var id_pobor = String()
let pin = FBAnnotation()
guard let tempUniqueE21 = get_sortedObjectsByDistance(i) else {
continue
}
let temp = tempUniqueE21
pin.coordinate = CLLocationCoordinate2D(latitude: tempUniqueE21.lat, longitude: tempUniqueE21.lng)
pin.title = temp.provoz
pin.subtitle = temp.ulice
self.clusteringManager.addAnnotations([pin])
self.arrOfPinsOnMap.append(pin)
}
}
I am calling this method overtime when user move with map. The problem is not with FB framework but with stored Annotation values.
I have two polylines on the map:
var polylineRoute : MKGeodesicPolyline!
var polylineFlight : MKGeodesicPolyline!
I assign each of them a title and add them to the map like this (in different methods):
let polyline = MKGeodesicPolyline(coordinates: &routeCoordinates, count: routeCoordinates.count)
polyline.title = "route"
self.mapView.addOverlay(polyline)
self.polylineRoute = polyline
and
let polyline = MKGeodesicPolyline(coordinates: &routeCoordinates, count: routeCoordinates.count)
polyline.title = "flight"
self.mapView.addOverlay(polyline)
self.polylineFlight = polyline
Now, when a specific action is triggered, I would like to remove only the flight overlay and leave the route overlay intact.
This does not work at all:
func removeFlightPath()
{
self.mapView.removeOverlay(self.polylineFlight)
self.polylineFlight = nil
}
The following works but removes both polylines:
func removeFlightPath()
{
var overlays = mapView.overlays
mapView.removeOverlays(overlays)
}
Is there a working way to remove only one polyline? I searched the forum and there is only one response that is saying that it is possible using the title. However, it does not specify how it can be done.
Thanks a lot!
EDIT:
This solves the issue:
func removeFlightPath()
{
if self.polylineFlight != nil
{
// Overlays that must be removed from the map
var overlaysToRemove = [MKOverlay]()
// All overlays on the map
let overlays = self.mapView.overlays
for overlay in overlays
{
if overlay.title! == "flight"
{
overlaysToRemove.append(overlay)
}
}
self.mapView.removeOverlays(overlaysToRemove)
}
}
I think your source code is correct. Could be that the reference counting is messing it up. As long as the object is referred to, MKGeodesicPolyline will not be removed. In your code, you have used a local variable to create the polyline object. I have tried it without using a local variable and it is removing the polyline.
self.polylineFlight = MKGeodesicPolyline(coordinates: &routeCoordinates, count: routeCoordinates.count)
self.polylineFlight.title = "flight"
polylineFlight doesn't look right. It's built from routeCoordinates, the same as polylineRoute. So removing it would produce no change in the map.
Are you building from the right coordinates?
Can we see before/after screenshots? Or can we see a clarification of "does not work at all"?