mapbox / mapbox-gl-native-ios

Interactive, thoroughly customizable maps for iOS powered by vector tiles and OpenGL
https://www.mapbox.com/mobile/
Other
210 stars 122 forks source link

App crashes if MGLSymbolStyleLayer.iconAnchor is set #552

Open RustamG opened 3 years ago

RustamG commented 3 years ago

The app crashes if I set MGLSymbolStyleLayer.iconAnchor property.

Steps to reproduce

I can reproduce the issue using Multiple Images example with just adding the following line:

layer.iconAnchor = NSExpression(forConstantValue: MGLIconAnchor.bottom)

So the full code is:

import Mapbox

@objc(MultipleImagesExample_Swift)

class MultipleImagesExample: UIViewController, MGLMapViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create and add a map view.
        let mapView = MGLMapView(frame: view.bounds, styleURL: MGLStyle.outdoorsStyleURL)

        // Center the map on Yosemite National Park, United States.
        mapView.setCenter(CLLocationCoordinate2D(latitude: 37.761, longitude: -119.624), zoomLevel: 10, animated: false)
        mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        mapView.delegate = self
        view.addSubview(mapView)
    }

    func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
        // Add icons from the U.S. National Parks Service to the map's style.
        style.setImage(UIImage(named: "nps-restrooms")!, forName: "restrooms")
        style.setImage(UIImage(named: "nps-trailhead")!, forName: "trailhead")
        style.setImage(UIImage(named: "nps-picnic-area")!, forName: "picnic-area")

        // Access a vector tileset that contains places of interest at Yosemite National Park. This tileset was created by uploading NPS shapefiles to Mapbox Studio.
        let url = URL(string: "mapbox://examples.ciuz0vpc")!

        // Add the vector tileset to the map's style.
        let source = MGLVectorTileSource(identifier: "yosemite-pois", configurationURL: url)
        style.addSource(source)

        // Create a symbol style layer and access the layer containin
        let layer = MGLSymbolStyleLayer(identifier: "yosemite-pois", source: source)

        // Access the layer that contains the POI data. The source layer identifier is a unique identifier for a layer within a vector tile source.
        layer.sourceLayerIdentifier = "Yosemite_POI-38jhes"

        // Create a stops dictionary with keys that are possible values for 'POITYPE', paired with icon images that will represent those features.
        let poiIcons = ["Picnic Area": "picnic-area", "Restroom": "restrooms", "Trailhead": "trailhead"]

        // Use the stops dictionary to assign an icon based on the "POITYPE" for each feature.
        layer.iconImageName = NSExpression(format: "FUNCTION(%@, 'valueForKeyPath:', POITYPE)", poiIcons)

// -----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
        layer.iconAnchor = NSExpression(forConstantValue: MGLIconAnchor.bottom)       // crashes here
// -----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
        style.addLayer(layer)

    }
}

Expected behavior

The app doesn't crash and iconAnchor is applied

Actual behavior

App crashes with error:

Thread 1: "-[__SwiftValue getValue:]: unrecognized selector sent to instance 0x280a91290"

Stack trace:

#0  0x00007fff2043a116 in __exceptionPreprocess ()
#1  0x00007fff20177f78 in objc_exception_throw ()
#2  0x00007fff20448c6f in -[NSObject(NSObject) doesNotRecognizeSelector:] ()
#3  0x00007fff2043e666 in ___forwarding___ ()
#4  0x00007fff20440698 in __forwarding_prep_0___ ()
#5  0x000000010ea7e80a in void MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue* __strong, mbgl::style::SymbolAnchorType, MGLIconAnchor>::getMBGLValue<mbgl::style::SymbolAnchorType, void, MGLIconAnchor, void>(objc_object*, mbgl::style::SymbolAnchorType&) at /Users/distiller/project/platform/darwin/src/MGLStyleValue_Private.h:257
#6  0x000000010ea6a3ab in std::__1::enable_if<!(std::is_same<mbgl::style::PropertyValue<mbgl::style::SymbolAnchorType>, mbgl::style::ColorRampPropertyValue>::value), mbgl::style::PropertyValue<mbgl::style::SymbolAnchorType> >::type MGLStyleValueTransformer<mbgl::style::SymbolAnchorType, NSValue* __strong, mbgl::style::SymbolAnchorType, MGLIconAnchor>::toPropertyValue<mbgl::style::PropertyValue<mbgl::style::SymbolAnchorType> >(NSExpression*, bool) [inlined] at /Users/distiller/project/platform/darwin/src/MGLStyleValue_Private.h:87
#7  0x000000010ea6a2f6 in -[MGLSymbolStyleLayer setIconAnchor:] at /Users/distiller/project/platform/darwin/src/MGLSymbolStyleLayer.mm:205
#8  0x000000010df2574f in MultipleImagesExample.mapView(_:didFinishLoading:) at /Users/rustamg/Documents/xCode/mapbox-ios-sdk-examples/Examples/Swift/MultipleImagesExample.swift:44

Configuration

Mapbox SDK versions: 5.9.0, 6.3.0 iOS/macOS versions: iOS 13.7, iOS 14. Device/simulator models: iPad 7th gen, also crashes on iPad Air 4 Simulator Xcode version: 12

avi-c commented 3 years ago

Hi @RustamG - You need to wrap the MGLIconAnchor enum value in an NSValue. e.g.

layer.iconAnchor = NSExpression(forConstantValue: NSValue(mglIconAnchor: .bottom))

The crash occurs because the value being sent to that expression is the wrong type so it isn't interpreted correctly at runtime.

RustamG commented 3 years ago

Thanks @avi-c