Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: ShapeSource.getClusterLeaves crash on iOS (NOBRIDGE mode) #3618

Open
villemuittari opened this issue Sep 10, 2024 · 0 comments
Open
Labels
bug 🪲 Something isn't working

Comments

@villemuittari
Copy link

villemuittari commented Sep 10, 2024

Mapbox Implementation

Mapbox

Mapbox Version

11.3.0

React Native Version

0.75.2

Platform

iOS

@rnmapbox/maps version

10.1.31

Standalone component to reproduce

import React, {useRef} from 'react';
import {Button} from 'react-native';
import {
  Images,
  MapView,
  ShapeSource,
  SymbolLayer,
  CircleLayer,
  Camera,
} from '@rnmapbox/maps';

const styles = {
  mapView: {width: '100%', height: 500},
  cluster: {
    circleRadiusTransition: {duration: 5000, delay: 0},
    circleColor: '#ff0000',
  },
};

const features = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      id: 'a-feature',
      properties: {
        icon: 'example',
      },
      geometry: {
        type: 'Point',
        coordinates: [-74.00597, 40.71427],
      },
    },
    {
      type: 'Feature',
      id: 'b-feature',
      properties: {
        icon: 'example',
      },
      geometry: {
        type: 'Point',
        coordinates: [-74.001097, 40.71527],
      },
    },
    {
      type: 'Feature',
      id: 'c-feature',
      properties: {
        icon: 'example',
      },
      geometry: {
        type: 'Point',
        coordinates: [-74.00697, 40.72427],
      },
    },
  ],
};

const BugReportExample = () => {
  const mapView = useRef<MapView>(null);
  const shapeSourceMarkers = useRef<ShapeSource>(null);

  const getVisibleMarkers = async () => {
    let visibleMarkers: any[] = [];
    const arrFeatures = await mapView.current?.queryRenderedFeaturesInRect(
      [],
      [],
      ['marker', 'cluster'],
    );
    if (!arrFeatures) {
      return visibleMarkers;
    }
    for (let index = 0; index < arrFeatures.features.length; index++) {
      const feature = arrFeatures.features[index];
      const properties = feature.properties;
      if (!properties) {
        continue;
      }

      if (properties.cluster) {
        try {
          // ====> THE FOLLOWING LINE CRASHES THE WHOLE APP <====
          const collection = await shapeSourceMarkers.current?.getClusterLeaves(
            feature,
            properties.point_count,
            0,
          );
          collection.features.forEach((f: any) => {
            visibleMarkers.push(f);
          });
        } catch (error: any) {
          console.debug('error', error);
        }
      } else {
        visibleMarkers.push(feature);
      }
    }
    console.debug('visibleMarkers', visibleMarkers);
    return visibleMarkers;
  };

  const circleLayerStyle = {
    ...styles.cluster,
    ...{circleRadius: 15},
  };

  return (
    <>
      <MapView style={styles.mapView} ref={mapView}>
        <Camera
          defaultSettings={{
            centerCoordinate: [-74.001097, 40.71527],
            zoomLevel: 10,
          }}
        />
        <Images images={{example: {uri: 'https://27crags-sandbox.s3.amazonaws.com/v6-icon.png'}}} />
        <ShapeSource
          id={'shape-source-markers'}
          ref={shapeSourceMarkers}
          shape={features}
          cluster={true}
          clusterRadius={30}
          clusterMaxZoomLevel={19}>
          <SymbolLayer
            id="marker"
            style={{
              iconImage: ['get', 'icon'],
              iconAllowOverlap: false,
              iconSize: 0.5,
            }}
            slot={'middle'}
            filter={['!', ['has', 'point_count']]}
          />
          <SymbolLayer
            id="pointCount"
            style={{
              textField: ['format', ['concat', ['get', 'point_count']]],
              textSize: 12,
              textPitchAlignment: 'viewport',
              textAllowOverlap: false,
            }}
          />
          <CircleLayer
            id={'cluster'}
            belowLayerID="pointCount"
            style={circleLayerStyle}
            slot={'bottom'}
            filter={['has', 'point_count']}
          />
        </ShapeSource>
      </MapView>
      <Button
        title="Count all items inside clusters"
        onPress={() => {
          getVisibleMarkers().then(visibleMarkers => {
            console.debug('visibleMarkers', visibleMarkers);
          });
        }}
      />
    </>
  );
};

export default BugReportExample;

Observed behavior and steps to reproduce

When trying to get clusterLeaves using the method getClusterLeaves() of ShapeSource the app crashes immediately.

0   libobjc.A.dylib               	       0x18005d44c objc_retain + 8
1   libobjc.A.dylib               	       0x1800856c0 objc_storeStrong + 44
2   RNLatest                      	       0x101870b78 -[RNMBXShapeSourceModule getClusterLeaves:featureJSON:number:offset:resolve:reject:] + 120 (RNMBXShapeSourceModule.mm:56)
3   CoreFoundation                	       0x1804b4720 __invoking___ + 144
4   CoreFoundation                	       0x1804b1a84 -[NSInvocation invoke] + 276
5   CoreFoundation                	       0x1804b1d1c -[NSInvocation invokeWithTarget:] + 60
6   RNLatest                      	       0x1012bc5c8 invocation function for block in facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*) + 240 (RCTTurboModule.mm:347)
7   RNLatest                      	       0x1012d2d90 facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2::operator()() const + 96 (RCTTurboModule.mm:380)
8   RNLatest                      	       0x1012d2d24 decltype(std::declval<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2&>()()) std::__1::__invoke[abi:ue170006]<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2&>(facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2&) + 24 (invoke.h:340)
9   RNLatest                      	       0x1012d2cdc void std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ue170006]<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2&>(facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2&) + 24 (invoke.h:415)
10  RNLatest                      	       0x1012d2cb8 std::__1::__function::__alloc_func<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2, std::__1::allocator<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2>, void ()>::operator()[abi:ue170006]() + 28 (function.h:193)
11  RNLatest                      	       0x1012d1a1c std::__1::__function::__func<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2, std::__1::allocator<facebook::react::ObjCTurboModule::performMethodInvocation(facebook::jsi::Runtime&, bool, char const*, NSInvocation*, NSMutableArray*)::$_2>, void ()>::operator()() + 28 (function.h:364)
12  RNLatest                      	       0x100e7b534 std::__1::__function::__value_func<void ()>::operator()[abi:ue170006]() const + 68 (function.h:518)
13  RNLatest                      	       0x100e7b454 std::__1::function<void ()>::operator()() const + 24 (function.h:1169)
14  RNLatest                      	       0x1012e25e4 invocation function for block in (anonymous namespace)::ModuleNativeMethodCallInvoker::invokeAsync(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, std::__1::function<void ()>&&) + 44 (RCTTurboModuleManager.mm:129)
15  libdispatch.dylib             	       0x180170104 _dispatch_call_block_and_release + 24
16  libdispatch.dylib             	       0x180171978 _dispatch_client_callout + 16
17  libdispatch.dylib             	       0x180179b10 _dispatch_lane_serial_drain + 960
18  libdispatch.dylib             	       0x18017a688 _dispatch_lane_invoke + 388
19  libdispatch.dylib             	       0x180185a84 _dispatch_root_queue_drain_deferred_wlh + 276
20  libdispatch.dylib             	       0x1801850d0 _dispatch_workloop_worker_thread + 448
21  libsystem_pthread.dylib       	       0x1042cb814 _pthread_wqthread + 284
22  libsystem_pthread.dylib       	       0x1042ca5d4 start_wqthread + 8

Expected behavior

ShapeSource.getClusterLeaves() used to worked on old architecture.

Notes / preliminary analysis

No response

Additional links and references

rnmapbox-getclusterleaves-crash.mov
@villemuittari villemuittari added the bug 🪲 Something isn't working label Sep 10, 2024
@github-actions github-actions bot reopened this Sep 10, 2024
@villemuittari villemuittari changed the title [Bug]: ShapeSource.getClusterLeaves crash on iOS (NOBRIDE mode) [Bug]: ShapeSource.getClusterLeaves crash on iOS (NOBRIDGE mode) Sep 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🪲 Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant