Identify operation for one of the layers does not work

2052
12
Jump to solution
07-29-2021 03:55 AM
bferrao
New Contributor

I am facing an issue in identify operation for one of the layers(Layer name is Service) in a map service.

Map is loaded on the mapview using the map service (AGSArcGISMapImageLayer)

        let basemap = AGSBasemap.streets()

        let map = AGSMap(basemap: basemap)

        

        // Map image layer.

        let mapImageLayer = AGSArcGISMapImageLayer(url: URL(string: "map service url”)!)

        // mapImageLayer.credential = AGSCredential(user: username, password: password)

        

        mapImageLayer.load { [weak mapImageLayer] (error: Error?) in

        }

        map.operationalLayers.add(mapImageLayer)

        

        // Assign map to the map view.

        mapView.map = map

 

        // Add self as the touch delegate for the map view.

        mapView.touchDelegate = self


Once the map is loaded, I zoom in to the "Service" feature so that it is visible. On tapping on the feature, the identify operation is performed:

// MARK: - AGSGeoViewTouchDelegate

func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {

        // Get the geoElements for all layers present at the tapped point.

        self.identifyLayers(screenPoint)

    }

    

    // MARK: - Identify layers

    private func identifyLayers(_ screen: CGPoint) {

        self.mapView.identifyLayers(atScreenPoint: screen, tolerance: 22, returnPopupsOnly: false, maximumResultsPerLayer: 10) { (results: [AGSIdentifyLayerResult]?, error: Error?) in

                        

            if let error = error {

                self.presentAlert(error: error)

            } else {

                self.handleIdentifyResults(results!)

            }

        }

    }

 

I am able to get the layer in the results (AGSIdentifyLayerResult) but the geo elements are empty. The Service feature is present at the tap point and is expected to be there in the geo elements array.

// MARK: - Helper methods    

    private func handleIdentifyResults(_ results: [AGSIdentifyLayerResult]) {

        var messageString = ""

        var totalCount = 0

        for identifyLayerResult in results {

            let count = self.geoElementsCountFromResult(identifyLayerResult)

           

            ......................

        } 

       .........

    }

    

    private func geoElementsCountFromResult(_ result: AGSIdentifyLayerResult) -> Int {

        // Create temp array.

        var tempResults = [result]

        // Using Depth First Search approach to handle recursion.

        var count = 0

        var index = 0

        

        while index < tempResults.count {

            // Get the result object from the array.

            let identifyResult = tempResults[index]

            

            // Update count with geoElements from the result.

            count += identifyResult.geoElements.count

            

            // Check if the result has any sublayer results.

            // If yes then add those result objects in the tempResults

            // array after the current result.

            if !identifyResult.sublayerResults.isEmpty {

                tempResults.insert(contentsOf: identifyResult.sublayerResults, at: index + 1)

            }

            

            for sublayerResult in identifyResult.sublayerResults {

                print("COUNT- \(sublayerResult.layerContent.name) \(sublayerResult.geoElements.count)")

            }           

     

            // Update the count and repeat.

            index += 1

        }

        return count

    }

In the above code, sublayerResult.geoElements.count is always 0 for the Service layer. For others, I am able to get the geo elements count.

The other layers of similar type (feature layer) and geometry(point) work fine when identify is performed and the features are available in the geo elements.

I am using ArcGIS Runtime iOS v100.9

 

Does someone face similar issue with any of the layers in a map service?  I could not find any solution /work around to fix this issue.
Any guidance is highly appreciated.

Thanks!

0 Kudos
1 Solution

Accepted Solutions
MarkDostal
Esri Contributor

@bferrao - it appears to be an issue with the service.  The fields below are causing the layer not to load:

  "typeIdField": "Subtype_Code",

  "subtypeFieldName": "Subtype_Code",

  "subtypeField": "Subtype_Code",

There is no "Subtype_Code"; instead it should be "Service.Subtype_Code".

The main problem wasn't the "Identify" operation, it was that the layer was unable to load (and therefore the Identify operation was never executed on the layer).

 

I'll direct message you with more details.

 

Mark

 

View solution in original post

0 Kudos
12 Replies
MarkDostal
Esri Contributor

@bferrao - Thank you for your question, hopefully we can come up with a solution for you.  There are a couple of things you should check:  does the service in question allow Queries? It's unlikely it doesn't, but you should check.  Also, is it possible that the results are more than two levels deep in the identifyLayerResult?

You are correct in that you need to drill down into the sublayer results, but you're only going one level deep;  is it possible the results are another level down?  

I've written some code which recursively returns a count of identified geoElements.  This will drill down to all levels of the sublayer results.

 

extension ViewController: AGSGeoViewTouchDelegate {
    func geoView(_ geoView: AGSGeoView, didTapAtScreenPoint screenPoint: CGPoint, mapPoint: AGSPoint) {

        // Identify graphics at the tapped location.
        mapView.identifyLayers(atScreenPoint: screenPoint,
                               tolerance: 10,
                               returnPopupsOnly: false,
                               maximumResultsPerLayer: 10
        ) { [weak self] (results, error)  in
            //check for errors and ensure identifyLayerResults is not nil
            if let error = error {
                print(error)
                return
            }
            guard let identifyLayerResults = results,
            let self = self else { return }

            var resultCount:Int = 0
            print("identifyLayerResults.count = \(identifyLayerResults.count)")
            
            // Loop through all results and get the count for those.
            for identifyLayerResult in identifyLayerResults {
                resultCount += self.getIdentifyLayerResultCount(identifyLayerResult)
            }
            print("result count = \(resultCount)")
        }
    }
    
    func getIdentifyLayerResultCount(_ identifyLayerResult: AGSIdentifyLayerResult) -> Int {
        var resultCount: Int = 0
        resultCount += identifyLayerResult.geoElements.count
        
        //process the sublayer results for each layer (e.g. for map image layers)
        print("identifyLayerResult.sublayerResults.count = \(identifyLayerResult.sublayerResults.count)")
        // Loop through each subLayerResult recursively and get their count.
        for subLayerResult in identifyLayerResult.sublayerResults {
            resultCount += getIdentifyLayerResultCount(subLayerResult)
        }

        return resultCount
    }
}

Definitely double-check the service and the possibility that results are deeper than the first sublayer.

Let me know if this doesn't resolve your issue or if you have more questions.

Mark

 

0 Kudos
bferrao
New Contributor

Thanks Mark for the code snippet!

I will try this code to drill down for multiple levels and see if it works.

0 Kudos
bferrao
New Contributor

@MarkDostal 
I checked the layer depth and it is one level deep. I added the recursive call as well.

I can also see the query operation is enabled for the Service layer. I tried to debug more by running the Identify operation on the specific feature layer directly.

 

let featureTable = AGSServiceFeatureTable(url: URL(string:"https:...WaterNetwork/MapServer/77")!)

 

        //create a feature layer

        self.featureLayer = AGSFeatureLayer(featureTable: featureTable)

        self.featureLayer!.load { (error) in

            self.mapView.identifyLayer(self.featureLayer!, screenPoint: screen, tolerance: 22, returnPopupsOnly: false) { (identifyLayerResult) in

                

                // Dismiss progress hud.

                SVProgressHUD.dismiss()

                

                if let error = error {

                                self.presentAlert(error: error)

                            } else {

                                let _ = self.getIdentifyLayerResultCount(identifyLayerResult)

                            }

            }

        }

I get this error while loading the feature layer.

Error Domain=com.esri.arcgis.runtime.error Code=3017 "Geodatabase field not found." UserInfo={NSLocalizedFailureReason=, NSLocalizedDescription=Geodatabase field not found., Additional Message=}

I believe this should be fixed at the map service level.

Can you please guide me on why/when do we get this error? or if I can isolate and find out which field has an issue here.

I will forward the details and ask the map service owner to make necessary changes to make it work.

Thanks for the help!!

 

 

0 Kudos
MarkDostal
Esri Contributor

@bferrao - Can you try the layer that gives you the load error in the ArcGIS Online Map Viewer?  This will help us figure out if it's an issue with the Runtime or the map service.  In the meantime, I'll try and get more information on that error.

Thanks,

Mark

0 Kudos
bferrao
New Contributor

There is another map service instance where I have similar problem with Identify problem with one of the layers.
In this case, the feature layer load and identify operation do not return any error. But I can see the below error in the result (AGSIdentifyLayerResult.error property).

Error Domain=com.esri.arcgis.runtime.error Code=3017 "The requested field was not found." UserInfo={NSLocalizedFailureReason=Insert values has a non-existent field., NSLocalizedDescription=The requested field was not found., Additional Message=Insert values has a non-existent field.}

I think there is something changed in iOS 100.9 SDK which now handles a missing field differently. The identify on the same map service works well in the older implementation of v100.4

Can I handle it by setting some parameter in identify/query request in the runtime app or should It be done on map service level?

Thanks for the help again!

 

0 Kudos
MarkDostal
Esri Contributor

@bferrao - I will get more information that error, but is it possible for you to retest with the latest version of the SDK, which is v100.11?  Even if you don't move your production code to 100.11, it would be helpful to see if the issue has been resolved between v100.9 and v100.11.

And as with your "load" error question, if you can try an identify with this layer in the AGOL Map Viewer that would help narrow down the cause of the issue.

Mark

0 Kudos
MarkDostal
Esri Contributor

@bferrao - I've got some more information.  For both of your issues it's hard to really determine what's going on without some more information.  It could be that the service is using a "reserved" fieldname that gets changed during the publishing process; in that case, it's possible the renderer wants to use a field that no longer exists, which could generate the error.

If you could provide us with either the service URL or JSON containing the service details (specifically the list of fields) we can dig into it further.

Thanks,

Mark

 
0 Kudos
bferrao
New Contributor

Hi Mark,

Here is the attached JSON file of the Service layer that is giving the issue.

 

Thanks,

Basil

0 Kudos
MarkDostal
Esri Contributor

@bferrao Hello, I wanted to follow up and see if you've been able to resolve your issue.

0 Kudos