My use case:
I have 19,000 annotations spread across the US.
Each annotation has a unique image.
I only show 20 annotations at a time as the user pans.
Problem:
After panning for awhile and loading a few hundred annotations (not all at once), it fails to show any more.
Here is how I remove and add annotations as the user pans:
-(void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
//This method only returns 20 objects
NSArray *myObjects = [dummyService getObjectsInVisibleRect:[mapView visibleCoordinateBounds].sw ne:[mapView visibleCoordinateBounds].ne];
NSMutableArray *newAnnotations = [[NSMutableArray alloc] init];
for(MyObject *myObject in myObjects) {
MGLPointAnnotation *point = [[MGLPointAnnotation alloc] init];
point.coordinate = [[myObject location] coordinate];
point.title = [myObject myIdentifier];
point.subtitle = [myObject myName];
[newAnnotations addObject:point];
}
NSArray *existingAnnotations = [_mapView annotations];
NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] init];
for(MGLPointAnnotation *existingAnnotation in existingAnnotations) {
//I actually subclass MGLPointAnnotation, such that isEqual and hash are implemented. In any case, the containsObject logic here works as intended
if([newAnnotations containsObject:existingAnnotation]) {
[newAnnotations removeObject:existingAnnotation];
} else {
[annotationsToRemove addObject:existingAnnotation];
}
}
if([annotationsToRemove count] > 0) {
[_mapView removeAnnotations:annotationsToRemove];
}
if([newAnnotations count] > 0) {
[_mapView addAnnotations:newAnnotations];
}
}
To be clear, the imageForAnnotation method fires, and a valid MGLAnnotationImage (inited with UIImage and a unique reuseIdentifier) is returned. However, the annotations stop showing up on the map.
I actually subclass MGLPointAnnotation, such that isEqual and hash are implemented.
Oh, good catch. Please feel free to submit a pull request with that functionality.
The iosapp demo application loads up to 10,000 points more or less simultaneously, and the only hard limit Iām aware of is UINT32_MAX (due to the type used for annotation IDs internally). So it sounds like this might be related to the overall number of additions and removals over time. Another possibility is that youāre running into a different form of #2956.
I think this is a duplicate of #1883.
I tried using the same reuseIdentifier (and by extension image) and it has no trouble showing as many annotations as I want. Is there a way to disable caching, or whatever the reuse identifier is used for?
I'm having the same issue. Just built from source (d11d53d).
The workaround described in https://github.com/mapbox/mapbox-gl-native/issues/2693#issuecomment-150090842 is not working for me. It looks like it's the same issue as #1883 or #2956.
I'm clustering around 16k annotations and only show 16 annotations at the same time, which are removed and added every time the map region changes. Everything works fine when using a single image with a single reuse id. But when I'm using unique reuse ids, annotations start disappearing.

Tried to debug this some more. The problem only seems to exist when there are a lot of different reuse ids. It doesn't matter if the image is drawn using UIGraphicsGetImageFromCurrentImageContext or loaded from file with UIImage(named: "test").
This seems fairly trivial to reproduce in the iosapp.
Here is how the app looks with 10,000 annotations with the current logic that uses a reuse identifier of 2 characters (99 permutations)

Here is how the app looks when you change the reuse identifier to be the entire string, not just the last 2 characters:

This was accomplished by changing line 482 of MBXViewController.mm to:
NSString *lastTwoCharacters = title; //[title substringFromIndex:title.length - 2];
FWIW, I'm able to reproduce this as well. Some observations:
dequeueReusableAnnotationImageWithIdentifier are all valid images. For whatever reason, they do not all render on the map.Let me know if anyone has found a workaround.
I've got a sample project at https://github.com/ChrisLowe-Takor/MapboxAnnotationLimitBug showing this bug.

This should be a 20x20 grid of numbered annotations. As @JohnRbk mentioned imageForAnnotation correctly returns the desired image and the accessory callout can be clicked but the annotation isn't rendered on the map.
I've played around with it a little and found that using smaller graphics increases the number of custom annotations that can be shown (over 100 in this demo, whilst my app bombs out around 30).
The root cause of this bug is #489. The sprite image data is still present, which is why hit testing continues to work. However, the SpriteAtlas is failing to allocate a new image based on the data, because with more annotation images or much larger annotation images, we start to run up against the 512Ć512 sprite sheet limit.
@jfirebaugh @ansis, can we at least increase the limit to 1024Ć1024 to mitigate #489?
Iām wondering whether another workaround would be for either MGLMapView or client code to remove annotation images that are unneeded (i.e., out of view), now that we have #3146 #3320. Thatād only address some of the examples posted above, unfortunately.
Unfortunately, #3530 exacerbates this bug. Now that sprites in the SpriteAtlas are unscaled, on a 2Ć display, weāre only able to squeeze in something like a fourth of the sprites. Even the āAdd 100 Pointsā demo runs up against the limit:

@1ec5 Can you elaborate? It seems like the only case in which #3530 would exacerbate this bug was if you were supplying lots of @2x icons on a device with @1x pixel ratio, which seems uncommon. The more common case of supplying @1x icons on a @2x device should actually consume _less_ space in the atlas, since they no longer get upscaled.
We can set debug::spriteWarnings to true to troubleshoot this. It will spew out a warning for SpriteAtlas overflow. IMHO, we should change the default value of this to true since it can happen even without annotations (Its more serious in that case since the map will silently be missing some icons).
@jfirebaugh, my bad, this regression wasnāt caused by #3530; I simply misremembered, expecting the 100 points to be distributed in the same way as in the 10,000-point demo. In fact, the stock demos are fine, and the steps in https://github.com/mapbox/mapbox-gl-native/issues/3185#issuecomment-166187254 reproduce exactly as before:

Sorry for the false alarm.
My project is severely hampered by this bug so I'll put my 2c.
MGLMapViewDelegate so they can attempt to deal with it.- (void) mapView:(MGLMapView *)mapView didFailToAllocationAnnotationImage: (id<MGLAnnotation) annotation
Iām still working on a way for developers to remove annotation images, building off #3146. The main holdup right now is that annotations whose images have been deleted wind up producing āsprite not foundā messages in the console (and hurting performance slightly, probably related). So Iām looking at replacing the deleted image with the default image. Failing that, Iāll have MGLMapView automatically remove those annotations and readd them with the default annotation image.
Iām still working on a way for developers to remove annotation images, building off #3146.
Proposed in #3835. Given the high impact, however, Iām putting that PR on the 3.2.0 milestone. 3.1.0 is going to ship with a 1024Ć1024 SpriteAtlas limitation.
Just ran into this issue, even though we add and remove annotations as need when the map region changes.
coordinate property.image property in a KVO-compliant way.The bug that this ticket tracks is still present in the SDK, but with these workarounds, this is as far as we expect to take the v3.3.0 milestone.
have a same issue. ios/swift/mapbox v.3.3.3
i generate many different images on the fly with CGContext for different annotations.
as soon as i have more than around 500 unique reuseIdentifier for the annotations image, everything above 500 isn't displayed anymore. annotation is set, but the image not.
extension showRouteController: MGLMapViewDelegate {
func mapView(mapView: MGLMapView, imageForAnnotation annotation: MGLAnnotation) -> MGLAnnotationImage? {
var image: UIImage
var reuseIdentifier = ""
//reuse identifier
switch(self.funcType) {
case .PrintMarker:
reuseIdentifier = "MarkerSpeed\(utils.getSpeed(globalSpeed.gSpeed))-1"
case .PrintBaseHeight:
reuseIdentifier = "MarkerSpeedBase\(utils.getSpeed(globalSpeed.gSpeed))-2"
case .PrintAltitude:
reuseIdentifier = "MarkerAlt\(Int(round(globalAltitude.gAltitude)))-3"
case .Recording:
reuseIdentifier = "MarkerCircleSpeed\(utils.getSpeed(globalSpeed.gSpeed))-4"
case .PrintCircles:
reuseIdentifier = "MarkerCircle\(utils.getSpeed(globalSpeed.gSpeed))-5"
default:
print("marker image default break")
break
}
var annotationImage = mapView.dequeueReusableAnnotationImageWithIdentifier(reuseIdentifier)
if annotationImage == nil {
image = imageUtils.drawLineOnImage(self.funcType)
annotationImage = MGLAnnotationImage(image: image, reuseIdentifier: reuseIdentifier)
}
return annotationImage
}
Since iOS SDK v3.3.x added view-based annotations, thatās our suggested workaround for use cases that require many unique or large images. You can see a basic implemention example here.
There are performance trade-offs, but views are generally more flexible and nicer to work with, anyway. š
To make sure the loop here is obviously and fully closed: the fix for this issue will be available in iOS 3.7.0, pre-releases of which are available now.