Platform:
iOS
Mapbox SDK version:
3.6.4
Here is the code that I'm using to try and do this. Here, the field annotation set object is just a struct that holds a pin annotation for the title of the field, and a multipoly for the actual geometry of the object. I have double-checked that this code is being called well after the map style is done loading.
func add(_ annotationSet: DCFieldAnnotationSet) {
self.addAnnotation(annotationSet.fieldPinAnnotation)
if let fieldName = annotationSet.fieldPinAnnotation.title {
if let source = style?.source(withIdentifier: fieldName) {
style?.removeSource(source)
}
if let styleLayer = style?.layer(withIdentifier: fieldName+"fillLayer") {
style?.removeLayer(styleLayer)
}
let source = MGLShapeSource(identifier: fieldName, shape: annotationSet.fieldMultiPoly, options: nil)
let styleLayer = MGLFillStyleLayer(identifier: fieldName, source: source)
styleLayer.fillColor = MGLConstantStyleValue(rawValue: DCMapStyle.polygonFillColor)
styleLayer.fillOpacity = MGLConstantStyleValue(rawValue: DCMapStyle.fillAlpha as NSNumber)
style?.addSource(source)
style?.addLayer(styleLayer)
}
}
I need to be able to remove and replace map sources and style layers with objects with the same identifiers.
I cannot remove and replace a source or a style layer without a duplicate object exception being thrown.
You may want to update the shape property on your source, rather than creating a new source. This allows the source to keep the original source identifier.
For example:
if let source = style?.source(withIdentifier: fieldName) {
source.shape = annotationSet.fieldMultiPoly
}
Not trying to reopen this. Just pointing out that I discovered in my own work that order matters. You need to remove the layer _before_ removing the source, e.g:
func removeLayer(mapView: MGLMapView, layerIdentifier: String){
guard let currentLayers = mapView.style?.layers else { return }
if currentLayers.filter({ $0.identifier == layerIdentifier}).first != nil {
print("Layer \(layerIdentifier) found.")
guard let mapStyle = mapView.style else { return }
// remove layer first
if let styleLayer = mapStyle.layer(withIdentifier: layerIdentifier) {
mapStyle.removeLayer(styleLayer)
}
// then remove the source
if let source = mapStyle.source(withIdentifier: layerIdentifier) {
mapStyle.removeSource(source)
}
}
else{
print("No layer with the identifier \(layerIdentifier) found.")
}
}
Most helpful comment
Not trying to reopen this. Just pointing out that I discovered in my own work that order matters. You need to remove the layer _before_ removing the source, e.g: