Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__SwiftValue objCType]: unrecognized selector sent to instance #14783

Closed
pappalar opened this issue May 28, 2019 · 4 comments
Labels
bug iOS Mapbox Maps SDK for iOS macOS Mapbox Maps SDK for macOS

Comments

@pappalar
Copy link

*** First throw call stack:
(
	0   CoreFoundation                      0x000000010fe5c6fb __exceptionPreprocess + 331
	1   libobjc.A.dylib                     0x000000010e383ac5 objc_exception_throw + 48
	2   CoreFoundation                      0x000000010fe7aab4 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
	3   CoreFoundation                      0x000000010fe61443 ___forwarding___ + 1443
	4   CoreFoundation                      0x000000010fe63238 _CF_forwarding_prep_0 + 120
	5   Mapbox                              0x0000000109d383ab -[NSExpression(MGLPrivateAdditions) mgl_constantMBGLValue] + 861
	6   Mapbox                              0x0000000109d2da9b -[NSDictionary(MGLAdditions) mgl_propertyMap] + 771
	7   Mapbox                              0x0000000109c9fabc _Z11mbglFeatureN6mapbox7feature7featureIdEEP11objc_objectP12NSDictionary + 214
	8   Mapbox                              0x0000000109ca1913 -[MGLPointFeature geoJSONObject] + 177
	9   Mapbox                              0x0000000109ca650e -[MGLShapeCollectionFeature geoJSONObject] + 430
	10  Mapbox                              0x0000000109cb6f0e -[MGLShapeSource setShape:] + 88

Steps to reproduce

  1. Create a Swift Class that inherits from MGLPolylineFeature
  2. Add a instance of this class to a a collection Feature: MGLShapeCollectionFeature(shapes: [yourInstance])
  3. Add this shape to one of your MGLShapeSource sources

Expected behavior

Mapbox uses the subclass of MGLPolylineFeature on the map

Actual behavior

App Crashes due to uncaught exception 'NSInvalidArgumentException', reason: '-[__SwiftValue objCType]: unrecognized selector sent to instance

Question:

Is it possible to subclass Style Primitives?

Notice: Same issue happens with subclasses of MGLPointFeature

Mapbox SDK versions: 5.0.0

@pappalar
Copy link
Author

On a secondary note.

Being MGLPolylineFeature a interface of protocol MGLFeature
is impossible from subclasses to call super.init(coordinates: coordinates, count: UInt(geometry.count)) as the initializer is not a designated one for the superclass

@julianrex julianrex added bug iOS Mapbox Maps SDK for iOS labels May 28, 2019
@1ec5
Copy link
Contributor

1ec5 commented May 28, 2019

The code that serializes the MGLPolylineFeature into GeoJSON is tripping over some Swift object in the attributes dictionary that has been cast into an NSValue but isn’t one, likely a Swift struct or enumeration. This document lists the types that are supported in attributes.

Being MGLPolylineFeature a interface of protocol MGLFeature
is impossible from subclasses to call super.init(coordinates: coordinates, count: UInt(geometry.count)) as the initializer is not a designated one for the superclass

Can you speak to why you’re trying to subclass MGLPolylineFeature? If you use an MGLFeature in a shape source, the original object gets lost anyways and you won’t be able to take advantage of your subclass when using runtime styling or feature querying.

@1ec5 1ec5 added the macOS Mapbox Maps SDK for macOS label May 28, 2019
@pappalar
Copy link
Author

It seems to me that the original issue was with a private struct shadowing another subclass struct.
I am using struct to wrap static let keys (attributes string keys).
After some reshaping of the struct I managed to get rid of the exception.

@1ec5 to the reason why:

I need to display a quite large amount of different features, each one with its own attributes used in the style for the rendering.
I later on need to interact on the map with those features and I would rather know which type of data I am passing around the app.

To simplify my life I am doing the following:

  • I created different subclasses of a concrete implementation of MGLFeature (eg: Polyline) that have a convenience initializers for my own different needs.
  • Internally each subclass is not storing any additional properties but configuring all rendering data in the attributes + storing any additional value I might need later also as an attribute.
  • The same subclass has an additional initializer that takes a MGLFeature (the one I read from the map) and internally copies over the attributes and coordinates.

This way when I interact with the map I can filter by layer, knowing then which subclass I am interacting with, create back the subclass and use computed properties to access all the attributes without the need to know which keys are used (as I have many and need the object across different part of the app)

This approach works for PointFeatures, as there is no convenience initializer for MGLPointAnnotation

so doing the following in a subclass works:

self.init()
self.coordinate = coordinate

However is currently failing for me for Polylines:

as I cant call the initializer MGLPolylineFeature(coordinates: coordinates, count: UInt(geometry.count)) in a subclass I am forced to do

super.init() // NSObject init??
self.appendCoordinates(coordinates, count: UInt(geometry.count))

which does not initialize correctly the Polyline and does not display it on the map.

There is any way I can initialize correctly a subclass of MGLPolylineFeature?

@pappalar
Copy link
Author

After trying all other possibilities and reading the source code I noticed that

super.init() // NSObject init??
self.setCoordinates(coordinates, count: UInt(geometry.count))

seems to be working as expected.

I think the reported things above will change in case #7454 somehow restructures things out

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug iOS Mapbox Maps SDK for iOS macOS Mapbox Maps SDK for macOS
Projects
None yet
Development

No branches or pull requests

3 participants