My app needs to know the rough location of a user, with a resolution of their state/province. This way we know what the default tax rate should be in a simple tax calculator. They can still pick it after that, but its always nice to try to get it right.
Is there an easy way to get this sort of resolution without all the rigamarole of callbacks and such? I don't need updates, a single rough location will do, and an old one is likely perfectly fine.
There are no short simple ways to get current location.
That means that you need init CLLocationManager object, call startUpdatingLocation method and retrieve result in delegate method.
It's impossible to get current location synchronously by using one line of code because retrieving location info could take much time (For example turning on GPS sensor and so on.). That's why you get info by asynchronous delegate methods.
is the only way,
but to get a single user position
within the method locationManager:didUpdateLocations: call stopUpdateLocation:
[locationManager stopUpdatingLocation]
Related
I'm using the background fetch method performFetchWithCompletionHandler in order to update some user data. However, those processes are fairly complicated and include block statements, so they don't execute synchronously.
My concern is that I am always returning completionHandler(UIBackgroundFetchResultNewData);
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Start background data fetch");
// Update data -- this method contains various blocks inside
[GETDataRequest updateUserDataWithUser: user];
// Update images -- this method contains various blocks inside
[GETImagesRequest updateUserImagesWithUser: user];
NSLog(#"Background Data Fetch completed");
completionHandler(UIBackgroundFetchResultNewData);
}
According to this post, in regards to completionHandler(UIBackgroundFetchResultNewData) the following was mentioned:
You have to call this to let iOS know what the result of your background fetch was. It uses this information to schedule future background fetches. If you neglect to do this, future background fetches may be delayed by the OS. The consequences of not calling this handler might include terminating your app altogether.
As you can see here, I am always saying it's successful whether or not it actually is. The answerer had this to say about my situation:
...you should call the completion handler only when your fetch is actually complete. Otherwise iOS will probably put your application back to sleep before the connection completes, and apps shouldn't actually be able to determine UIBackgroundFetchResultNewData versus UIBackgroundFetchResultNoData or UIBackgroundFetchResultFailed until then anyway. How do you know your connection will succeed?
Is what I'm doing ACTUALLY a problem? Will it actually cut off the updates? If it is going to produce unexpected results, what's the solution to this mess? The answer to the question I mentioned wasn't clear enough to me. I have tried using block variables to make it function as it should, but have been unsuccessful. Much appreciated.
The code you are using is meant for Background Fetch Refresh functionality, through this you can make a quick refresh to your app when its in background by mentioning the system time interval to minimum. This service is available in the delegate method performFetchWithCompletionHandler and it will last for 30 seconds. You need to manage your code accordingly to get updated result and then at end as per your result you need to call the appropriate completion handler block.
If you have the long running background task I will prefer then to use Background Fetch Services using NSURLSessions.
I'm trying out iBeacons now.
I have 2 devices that I'm using as beacons and 1 device to do the ranging.
When I implemented this method call locationManager:didRangeBeacons:inRegion:, in the documentation it says that "didRangeBeacons" takes an array of beacons in the proximity.
However, what I'm noticing is that locationManager:didRangeBeacons:inRegion: is getting called twice by each individual beacons. Is it supposed to behave that way?
Thanks,
Tee
You are supposed to get one call per second to locationManager:didRangeBeacons:inRegion for each CLBeaconRegion that you are ranging, and this callback includes an array of the CLBeacon objects that are seen inside that region.
So if you have set up two CLBeaconRegion objects and are ranging on both of them, you should two callbacks per second, each with a single beacon in its array.
If you have set up a single CLBeaconRegion for ranging that matches both beacons, then you should only get one callback per second and it should contain two beacons in its array.
You're right that locationManager:didRangeBeacons:inRegion gets called multiple times - when the proximity of beacons changes. I thought I read that this was usually once per second (and my testing would seem to align with this) but I can't find a reference for it at the moment.
You can of course decide what action you want to take whenever the method gets called (or even to take no action at all). You could also call stopRangingBeaconsInRegion: if you only want to be notified once.
In the process of learning iOS development and I am currently being taught how to use the core location framework.
I'm told that we need to create an instance of CLLocationManager, and then set a delegate, then implement this method:
-(void) locationManager: (CLLocationManager*)manager
didUpdateToLocation: (CLLocation*)newLocation
fromLocation: (CLLocation*)oldLocation
The book doesn't thoroughly explain how the location is actually received. From what I'm understanding, whenever locationManager logs a new location, it then sends a message (to the delegate?) with the selector being the above method, filling the parameters with the location data? Then we must implement this method and choose what to do with these parameters.
Is this correct? and if not, could someone explain to me exactly what is going on?
Thanks in advance, this is confusing me a ton.
Right, although the message you should implement starting in iOS 6 is -locationManager:didUpdateLocations:. After setting up the delegate, call -startUpdatingLocation and the Location Manager will start sending -locationManager:didUpdateLocations: (or the other method) whenever the location changes until you tell it to stop. Your implementation of that method an do whatever you like -- update a position on a map, log the location to a file, look up the nearest gas stations... There's some reason that you're asking for location updates, and whatever that reason is, this lets you do it.
I have an app that tracks a users driving trips (Paths). I save all the information using Core Data.
The db structure:
Path ->> Point
Point contains lat and long values.
What I do is, each time CLLocationManager is updated I add that point to an array. Once the user has reached the end of the path, I loop through and add all those locations to the db.
My question is...is this the best way to go about this? My two options are:
Add all locations to array, then add all locations to core data.
Each time CLLocationManager is updated, add that directly to core data.
I'm not sure if there is some best practice to accessing/altering core data. Should I do it in bulk (for loop), so that I can call
if ([managedObjectContext save:&error]) {
// handle save error
}
at the end of the for loop and keep it all condensed.
Or should I simply add a new Point each time CLLocationManager updates calling [managedObjectContext save:&error] after each update.
The only concern I have with Option1 is that if the app crashes while recording a path, none of the information will be saved.
So a benefit of using Option2 is that the data will be saved after each update but I'm not sure if accessing core data this frequent is bad practice.
Thank you very much for taking the time to help.
With the assumed frequency of NSLocationManager updates (max every few seconds) it is absolutely fine to save frequently. Also, your array will eat up more and more memory which is not really necessary.
You could still do it in discreet quantities, say, one save every 10 points.
Also you should perhaps save in applicationWillResignActive in case the app is interrupted.
I'm working on a web application that enables users to login, only at specific locations. I'm using CLLocationManager and I initialized and called startUpdatingLocation at AppDelegate -didFinishLaunchingWithOptions. My UIWebView is supposed to pull the location at initialization to determine whether user's within the specified locations. However, at the launch of my application, [locationManager location] is always null and updates after my UIWebView is initialized and displayed therefore already sending an error message to the user.
How do I make my locationManager update its location at initialization?
Sounds like you've coded the location stuff correctly. What you are missing (but have seen) is that the update most certainly does not happen instantaneously. You need to "gate" the rest of your UI's presentation (i.e. your webview) on the location information becoming available. There are a lot of ways to do this. A common tactic is to present a full-screen "HUD" or veil with some indicator to the user that the app is initializing or locating them (with an activity indicator, too, is always a nice touch.) Behind that (out of sight to the user) you can be waiting for the location result and then kickoff the appropriate UI update, and then drop the veil.
Any of that make sense or give you some ideas? I've done this plenty of times. Synchronizing async activities (like location updates) with real-time UI updates that make sense can be challenging, but isn't impossible. :-)
You will need to account for an initial nil value in your applications UI and wait for the first location update.
-location
Discussion
The value of this property is nil if no location data has
ever been retrieved.
It is a good idea to check the timestamp of the location that is
returned. If the receiver is currently gathering location data, but
the minimum distance filter is large, the returned location might be
relatively old. If it is, you can stop the receiver and start it again
to force an update
Also you should check out Region Monitoring since you would like for you users to only be able to login at specific locations.