Query a feature layer without adding the layer to the map

436
6
Jump to solution
09-24-2018 07:57 AM
AsifIsmail
New Contributor III

hello all,

i have a feature layer which gets queried on each location change,the layer doesnt have anything to draw on the map.

so i wish not to add it to the map view.

the problem is that when i dont add the layer to the map,methods of AGSQueryDelegate doesnt get called,

if i add,the problem is for each location my code gets executed(which has to be) but the same layer gets added to the map again and again,

is there a way to query the layer without adding it to the map,im using esri sdk 10.2.5

please give me an idea to solve this..

0 Kudos
1 Solution

Accepted Solutions
Nicholas-Furness
Esri Regular Contributor

Hey Jake,

In the 10.2.x Runtime (which Asif is using) that's what the AGSQueryTask does (plus it integrates with the credential cache). Just initialize it with a URL to the service, and start firing queries against it. The NSOperation you get back can be cancelled if need be.

In the 100.x runtime, you can hold on to a reference to an AGSServiceFeatureTable that you load once and query against often (actually, you don't need to load it explicitly - any calls to query will take care of loading it). You don't need to create a layer from it or add it to a map. And when you run a query against it, you get back an AGSCancelable, which you can… as you might expect… cancel

The only limitation is that you can't list specific fields for the query. There's a sort of workaround for that involving setting the featureRequestMode to manualCache and populating the table using the query and fields you're after, then querying the table (which will run off the local cache and return immediately), but that is admittedly a bit tricky and if you have parallel queries going on with different field sets you'd want to have separate table instances; one for each field set.

Lastly, 10.2.x's AGSQuery.returnGeometry and 100.x's AGSQueryParameters.returnGeometry can be set to false to prevent geometry being returned.

Asif: If you can't control CLLocationManager.distanceFilter, then in your locationUpdate handler you could use AGSGeometryEngine.distanceFromGeometry:toGeometry() to see how far the new point is from that last acceptable point, and only fire a query once the distance has reached a threshold. So, you're still getting as many updates from CoreLocation, but you're not firing queries off until you've moved a sensible amount.

Also, in your sample code, before your "do" block, set up a "let trafficSpeedLayer = ..." there. Right now, as soon as your "do { }" block exits, your trafficSpeedLayer is being deallocated, and so the query callbacks have nothing to latch on to when they happen.

Cheers,

Nick

View solution in original post

0 Kudos
6 Replies
Nicholas-Furness
Esri Regular Contributor

Sounds like you are not holding on to the instance of the layer, so it's going out of scope and being destroyed before the query callback. When you add a layer to the map view, it's being retained by the map view so you're seeing results.

Create an object property (rather than a function variable) to hold on to the layer reference and you will get the completion called. You only need to create one instance of the layer and can query it multiple times. You should not create an instance each time your location updates.

Sounds like this could be causing the issue in your other question: Querying feature on device location change  

Nick.

0 Kudos
AsifIsmail
New Contributor III

this is what i have done,

i have created a class which extends AGSFeautureLayer which has callbacks for query

and in my view controller,when the location changes i have made an instance of this class and query the above layer with the new latlng as the geometry(i know this is bad,each time a new instance of the above class is recreated)

as of now,i manually deinit the created object after its value is read,so only one object of extended feature class is in memory at a time,

this seems like a hackfix for me,i want a better solution,could you please give me an example of what you have mentioned,

I have tried creating the global instance of the extended feature layer and just quering the layer when location gets changed,but in this case ,the layers callback doesnt get triggered?

i can show you my code,if you need

layer class : [Swift] TrafficLayer - Pastebin.com 

method on location change : [Swift] do { print("\(locations[0].coordinate.longitude)","\(locati - Pastebin.com 

0 Kudos
JakeShapley
New Contributor III

Hello Asif,

First, I've run into similar use cases before, and found it's easier to just write my own http call to the feature service endpoint. It's pretty straightforward (Query (Feature Service/Layer)—ArcGIS REST API: Services Directory | ArcGIS for Developers ) , and if you need to authenticate, you can just hit the generate token service first (Generate Token—ArcGIS REST API: Services Directory | ArcGIS for Developers ). This has several advantages, including a) you aren't creating a new layer, waiting for it to load, etc.; b) you can set returnGeometry to false and even limit outfields to the one(s) you need. Also, you could add a variable to track query status to cancel your request before making a new one.

Second, you can dial back the frequency of updates from the location manager by setting a distanceFilter (distanceFilter - CLLocationManager | Apple Developer Documentation) which is none by default. If the user is driving, several (or tens) of meters may be appropriate.

Please let me know if this helps, or you have any questions.

Cheers,

Jake

AsifIsmail
New Contributor III

Thanks jake,

that seems to be a good solution,

it would be better if you can point me to a working example

but i fear your second point about the distancefilter, i already have the location request setup without a distance filter, and its a legacy code base,

and i query the layer in the callback for locationupdate,i dont think it would be possible to set distancefilter in this case ..

what do you think ?

0 Kudos
Nicholas-Furness
Esri Regular Contributor

Hey Jake,

In the 10.2.x Runtime (which Asif is using) that's what the AGSQueryTask does (plus it integrates with the credential cache). Just initialize it with a URL to the service, and start firing queries against it. The NSOperation you get back can be cancelled if need be.

In the 100.x runtime, you can hold on to a reference to an AGSServiceFeatureTable that you load once and query against often (actually, you don't need to load it explicitly - any calls to query will take care of loading it). You don't need to create a layer from it or add it to a map. And when you run a query against it, you get back an AGSCancelable, which you can… as you might expect… cancel

The only limitation is that you can't list specific fields for the query. There's a sort of workaround for that involving setting the featureRequestMode to manualCache and populating the table using the query and fields you're after, then querying the table (which will run off the local cache and return immediately), but that is admittedly a bit tricky and if you have parallel queries going on with different field sets you'd want to have separate table instances; one for each field set.

Lastly, 10.2.x's AGSQuery.returnGeometry and 100.x's AGSQueryParameters.returnGeometry can be set to false to prevent geometry being returned.

Asif: If you can't control CLLocationManager.distanceFilter, then in your locationUpdate handler you could use AGSGeometryEngine.distanceFromGeometry:toGeometry() to see how far the new point is from that last acceptable point, and only fire a query once the distance has reached a threshold. So, you're still getting as many updates from CoreLocation, but you're not firing queries off until you've moved a sensible amount.

Also, in your sample code, before your "do" block, set up a "let trafficSpeedLayer = ..." there. Right now, as soon as your "do { }" block exits, your trafficSpeedLayer is being deallocated, and so the query callbacks have nothing to latch on to when they happen.

Cheers,

Nick

View solution in original post

0 Kudos
AsifIsmail
New Contributor III

Great information Nick,

Thanks for your detailed response..I'll use AGSQueryTask,

also,Jake's information was valuable..