So normally when you try to grab a user's location using CLLocation, you'll use the didUpdateLocations method which(if everything has gone well) will be called when using locationManager.startUpdatingLocations().
But I need to be able to manually call the function that gets the location so I can use a completion handler with it. How would I be able to get the user's location after start updating locations without using the didUpdateLocations method?
You can't "manually call CLLocation". After you start updating locations, the system begins calling your didUpdateLocations method. The first locations you get may have pretty poor accuracy. To get a good location you really need to check the accuracy and wait until you get a location that meets your requirements before you accept it.
I haven't used the new requestLocation method yet, so I don't know how it acts with regard to the poor results you get when you first request locations. The docs say "The location fix is obtained at the accuracy level indicated by the desiredAccuracy property" but supposedly startUpdatingLocations also honors the desired accuracy and the first few readings you get from it tend to be quite bad if the GPS was off when you called startUpdatingLocations.
In any case, both approaches call didUpdateLocations with the result/results.
If you want to invoke a closure/completion handler once you obtain a location then I suggest you create your own location manager singleton. Let's call it MyLocationManager.
You could give it a method getLocation(completion:) and have it take a completion block. The implementation would either start location updates or call requestLocation (if that method gives back locations that are dependably good the first time). It would also save away the completion handler closure in an (optional) instance variable. In MyLocationManager's implementation of didUpdateLocations it would check for a completion handler and call it if one was found, and then nil out the completion handler.
You can access the CLLocationManager's location property at any time. This will have the most recently determined location. It may be nil if no location has been determined.
If you are targeting iOS 9 & later then you can use the requestLocation method to request a single location update. The location update will be delivered to didUpdateLocations as usual. There is no synchronous/blocking "request location, wait for it to update and return the location to me" method.
Related
I am creating a class named WeatherService that based on a location will provide the weather forecast (surprise!). There are multiple things that could go wrong here; the location is not found, weather service is not reachable, ...
The service has a method named weatherFor taking a location object as argument. It is asynchronous.
I am using Swift 2. So I have been reading about error handling in Swift 2.0 and there seems to be one way that multiple sources describe and that is a closure with ResultType with a success handler and an error handler. Should I use that? Or should I create a delegate and pass the error like many of the framework objects does such? I already have a delegate for the weather service since I need to know when it starts, when it is done etc.
The delegate protocol has methods like:
Started weather forecast search
Ended weather forecast search
But I don't know if I also should add a method in the delegate that is invoked when something bad happens inside the weather service communicating that an error occured and the weather forecast couldn't be found, or if that is bad? I guess delegates with "error methods" that are invoked isn't bad in Swift?
If you have only one other object interested in receiving notifications about progress, errors etc you can either go with a closure or delegate. It sort of depends on when and where the errors can occur. If you only need to pass on errors or state when making the weatherFor call you can use the closure solution. If errors can happen "anytime", even after - or before - getting the weather, you should use the delegate solution. Or a combination of both.
One other way of doing it is to post notifications when errors occur. This means that more than one object can listen in on updates at the same time.
My requirement here is to get the user's current location and pass to map.google.com. And the most imp condition is : these two events must happen in a single method.
And my problem here is , I have to pass the user's location, but it is only obtained through the delegate of CLlocationManager.Basically i need user's location before calling for map.google.com.
(imp: i can't call for CLLocationManager in my viewwillappear or anywhere else in the code)
So, can we solve this issue using block handler?
Any help,links would be appreciated.
One of several solutions could be to use a third party library. Here one I used for geolocation, very light, simple, and blockbased : https://gist.github.com/steakknife/6972228
EDIT :
Here's an example to easily find the current location in one-line way using the synchronous method currentLocationByWaitingUpToMilliseconds:success: of the little library quoted above :
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:1000 success:nil];
I have an app that requires Geocoding from a string to lat/long values, I use the geocoder from the iOS class reference:
http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLGeocoder_class/Reference/Reference.html#//apple_ref/occ/cl/CLGeocoder
but the completion handler gets called after I need it to be (namely I have code that uses those lat/long values, but is getting called before they are available)
any thoughts?
Put the code that uses the lat-long into the geocoder's completion handler. That's what it's for.
So, as of iOS 6, -locationManager:didUpdateToLocation:fromLocation: is deprecated.
Apple suggests, instead, using -locationManager:didUpdateLocations:, which provides anywhere from one to a series of recent location changes. However, in the incredibly likely chance it provides a locations array of length 1, there appears to be no way to access the fromLocation:(CLLocation *)oldLocation parameter of old.
Is there a way to get at this information without using deprecated methods?
You just need to set a property to the value that locationManager:didUpdateLocations: returns, which you can use as the fromLocation, and then call the method again, and use what it returns as the toLocation.
As rdelmar said, if you need the previous location, I would just store the last location received from locationManager:didUpdateLocations: in an ivar or property, and if locationManager:didUpdateLocations: returns an array with only one value, grab the value you previously saved in your ivar/property and use that for your "old" location.
I am using CLLocation manager to get my lat & long, and it seems to work rather well. However, the first reading of accuracy no matter what, is always 10. From here it seems to home-in correctly starting at about 1500m. The reason that this is a problem is because to determine whether the method is called, I am checking if the accuracy is below 15, which this false reading is, and therefore calling the method at the wrong time. How do I get around this?
CoreLocation may cache some old location values to "speed up" first location update. You can see if your location is a new one by checking CLLocation's timeStamp property.
you can check using horizontal accuracy there are many posts in stackoverflow regarding cllocationmanager. And for calling a method you can use NSNotificationCenter,Deleagate & protocol mechanism and IBAction of course. It depends on your requirement.