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