CLGeocoder delay until completion handler - ios

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.

Related

Swift Selector on UIScreen brightness returning UIDevice when invoked

I have the following snippet
let classByName = objc_lookUpClass("UIScreen")
let mainScreen = (classByName as? NSObjectProtocol)?.perform(Selector("mainScreen"))?.takeRetainedValue()
print(mainScreen) // Optional(<UIScreen: ....
print(mainScreen?.perform(Selector("brightness")).takeUnretainedValue()) // Optional(<UIDevice:...
As you can see the second method returns a reference to the current UIDevice instead of the CGFloat corresponding to a screen brightness...
Any idea on what's going on here?
You run into a corner case due to using dispatch methods that are not recommended in Swift.
Please note that everything you read below is related to the Objective-C message passing (aka method calling). When interoperating with Objective-C classes, the Swift compiler generates (more or less) the same caller code as the Objective-C compiler, so anything that applies to Objc, also applies to Swift code calling ObjC.
First of all, performSelector should not be used on methods that return float, since behind the scenes performSelector calls objc_msgSend, however for methods that return a float, the internal result of objc_msgSend is read from the wrong location.
A little bit of background of objc_msgSend - this function is at the core of the Objective-C dynamic dispatch, basically any method call on an Objective-C object results in objc_msgSend being called. I won't get into too many details here, there are many online materials about objc_msgSend, just want to summarize that the function is a very versatile one, and can be casted to match any method signature.
So, let's take the brightness example. What actually happens behind the scenes when using performSelector (the Objective-C method named in Swift perform(_:))? This is roughly how performSelector is implemented:
- (void)performSelector:(SEL)selector) {
return objc_msgSend(self, selector);
}
Basically the method simply forwards the value resulted by calling objc_msgSend.
Now the things get interesting. Because floats and ints use different return locations, the compiler will need to generate different reading location depending on its knowledge about the type of data returned by objc_msgSend.
And if there's a misunderstanding between what the compiler thinks objcSend will return, and what actually the function returns, then bad things might happen. But in your case there's a "fortunate" coincidence due to which your program doesn't crashes.
Basically your perform(Selector("brightness") call results in a objc_msgSend(mainScreen, Selector("brightness")) call that assumes that objc_msgSend will return an object. But in turn the called code - the brightness getter - returns a float.
So why isn't the app crashing when the Swift code tries to print the result (actually it should crash on takeUnretainedValue)?
It's because floats and ints (and object pointers are in the same category as int) have different return locations. And the performSelector reads from the return location for ints, as it expects an object pointer. Fortunately, at that point in time, the last method called is likely a method that returns an UIDevice instance. I assume that internally UIScreen.brightness asks the device object for this information.
Something like this happens:
1. Swift code calls mainScreen?.perform(Selector("brightness")
2. This results in Objective-C call [mainScreen performSelector:selector]
3. objc_msgSend(mainScreen, selector) is called
3. The implementation of UIScreen.brightness is executed
4. UIScreen.brightness calls UIDevice.current (or some other factory method)
5. UIDevice.current stores the `UIDevice` instance in the int return location
6. UIScreen.brightness calls `device.someMemberThatReturnsTheBrightness`
7. device.someMemberThatReturnsTheBrightness stores the brightness into
the float return location
8. UIScreen.brightness exits, its results is already at the proper location
9. performSelector exits
10. The Swift code expecting an object pointer due to the signature of
performSelector reads the value from the int location, which holds the
value stored at step #5
Basically, it's all about calling conventions, and about how your "innocent" code gets translated into assembly instructions. This is why the fully dynamic dispatch is not recommended, because the compiler doesn't have all the details to construct a reliable set of assembly instructions.

Swift: How to manually call CLLocation

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.

AVSpeechUtterance completion handler

How do I set a completion event on the SpeakUtterance(utterance) function in Swift? I need this so that my speech is neither interrupted nor interrupting.
Have you looked at the header (or generated Swift interface) for AVSpeechSynthesizer? Or its documentation? Looks pretty straightforward there...
Set an instance of one of your classes as the delegate of the speech synthesizer.
In that class, implement the speechSynthesizer(_:didFinishSpeechUtterance:) method. It'll be called whenever an utterance finishes speaking.
There's no step three.

Getting user's current location before doing next event in single method?

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];

How to Find Which Ocean a Coordinate is on

I have some coordinates, which will always be somewhere in an ocean. I need a way to convert the coordinates into a string telling which ocean/sea the coordinate falls. Is there any convenient way to do this?
Thanks
If you're using MapKit, you can use the CLGeocoder method – reverseGeocodeLocation:completionHandler: to perform a reverse geocoding request. The completion handler returns an array of CLPlacemark objects. If you take a look at the CLPlacemark Class Reference, you'll see that there is an ocean property that contains the name of the ocean associated with the placemark. I'm assuming this will also apply to seas; if not, try the inlandWater property instead.
You can use reverse geocoding API: https://developers.google.com/maps/documentation/geocoding/#ReverseGeocoding https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse

Resources