Platform: iOS 10.2
Mapbox SDK version: 3.4.1
After seeing so many changes to the Mapbox iOS SDK, especially runtime styling, what is the recommended way of replacing an MGLShapeSource?
I'm currently facing an issue with the following code:
func updateSource(shapes: [MGLShape]) {
if let currentSource = mapView.style?.source(withIdentifier: sourceName) as? MGLShapeSource {
mapView.style?.removeSource(currentSource)
}
let newSource = MGLShapeSource(identifier: sourceName, features: shapes, options: nil)
mapView.style?.addSource(newSource)
if mapView.style?.layer(withIdentifier: layerName) == nil {
let layer = MGLSymbolStyleLayer(identifier: layerName, source: newSource)
[...setting some layer properties...]
mapView.style?.addLayer(layer)
}
}
After calling the above method twice in a short period of time, the symbols don't show up on the map anymore.
By the way: My current way of replacing shapes is the following but I'm not sure if it's the recommended way.
if let currentSource = mapView.style?.source(withIdentifier: sourceName) as? MGLShapeSource {
let collection = MGLShapeCollectionFeature(shapes: newShapes)
currentSource.shape = collection
}
After calling the above method twice in a short period of time, the symbols don't show up on the map anymore.
My current way of replacing shapes is the following but I'm not sure if it's the recommended way.
in updateSource it looks like you are removing the source and adding back again but only adding a layer with the original new source once. I think you could get this to work but you would need to remove the layer, too, and add it back with the updated (new) source each time.
Instead, I think you should be able to get the reference to the existing source currentSource and, instead of removing it, just update its shapes. There is an Objective-C example in the test iosapp that illustrates updating a shape source's shape property.
Beware that there is a fine line between a "shape" and a "feature" and it can be bothersome to work with in 3.4.x (ref https://github.com/mapbox/mapbox-gl-native/issues/7913)
Thanks @boundsj
So I think I'm doing it right (as shown in my previous comment by updating the shape property). I already realised that there is a difference between them but I couldn't see a difference between MGLShapeCollectionFeature and MGLShapeCollection. The implementation of both is the same
open var shapes: [MGLShape] { get }
public convenience init(shapes: [MGLShape])
The only difference is that MGLShapeCollectionFeature implements MGLFeature, but why? I don't see any use case for this.
Speaking of #7913: I also encountered this issue. Is this a bug of v3.4.x or desired behaviour?
The only difference is that MGLShapeCollectionFeature implements MGLFeature, but why? I don't see any use case for this.
You are working with GeoJSON. There is a distinction between a shape and a feature. The former is a geometry and the latter contains a geometry but also metadata (i.e. attributes in the Mapbox iOS SDK parlance). Attributes allow you to set properties that can later be used to do things like power data-driven styling (DDS) or the filter predicate API while pure shapes (with no attributes) can be visualized but cannot be affected by DDS or filters.
Speaking of #7913: I also encountered this issue. Is this a bug of v3.4.x or desired behaviour?
I'm actually not working with GeoJSON (my datasource is GeoJSON but it is parsed to Realm objects which then are reloaded to custom MGLFeature objects). I tried to subclass MGLPointFeature but it didn't work as expected, see #7949. So basically I have the following class:
class RestaurantPointFeature: MGLPointFeature {
fileprivate let restaurant: Restaurant
init(_ restaurant: Restaurant) {
self.restaurant = restaurant
super.init()
self.coordinate = restaurant.coordinate
self.attributes["id"] = restaurant.id
...
}
}
An array of [RestaurantPointFeature] is then passed to the MGLShapeSource initializer. So my question remains: Why is the MGLShapeCollectionFeature also of type MGLFeature? Is there some use case where a collection of shapes need to have a coordinate?
I'm actually not working with GeoJSON
Sorry, I meant that you are working with the Mapbox iOS SDKs object which are an abstraction of GeoJSON. MGLShapeCollectionFeature implements the MGLFeature protocol and has an attributes property that allows you to use it with DDS and filter APIs. MGLShapeCollection does not.
You may also find this guide useful: https://www.mapbox.com/ios-sdk/api/3.4.1/working-with-geojson-data.html
Closing. We will continue track the issue of MGLShape / MGLFeature conversion in https://github.com/mapbox/mapbox-gl-native/issues/7913
Most helpful comment
By the way: My current way of replacing shapes is the following but I'm not sure if it's the recommended way.