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.
Related
When calling the method
- (void)readPacketsWithCompletionHandler:(void (^)(
NSArray<NSData *> *packets, NSArray<NSNumber *> *protocols))completionHandler;
the completionHandler is either called directly, in case packets are available at call time, or it is called at a later tim when packets become available.
Yet what is nowhere documented is: What happens if I call this method again before the prior set completionHandler has ever been called?
Will the new handler replace the prior set one and the prior set one won't get called at all anymore?
Are both handler scheduled and called as data arrives? And if so, will they be called in the order I passed them, in reverse order, or in random order?
Has anyone any insights on how that method is implemented?
Of course, I can make a demo project, create a test setup, and see what results I get through testing but that is very time consuming and not necessarily reliable. The problem with unspecified behavior is that it may change at will without letting anyone know. This method may behave differently on macOS and iOS, it may behave differently with every new OS release, or depending on the day of the week.
Or does the fact that nothing is documented is by intention? Do I have to interpret that as: You may call this method once and after your callback was executed, you may call it again with the same or a new callback. Everything else is undefined behavior and you cannot and should not rely on any specific behavior if use that API in a different manner.
As nobody has replied so far, I tried my best to figure it out myself. As testing is not good enough for me, here is what I did:
First I extracted the NetworkExtension framework binary from the dyld cache of macOS Big Sur using this utility.
Then I ran otool -Vt over the resulting binary file to get a disassembler dump of the binary.
My assembly skills are a bit rusty but from what I see the completionHandler is stored in a property named packetHandler, replacing any previous stored value there. Also a callback is created in that method and stored on an object obtained by calling the method interface.
When looking at the code of this created callback, it obtains the value of the packetHandler property and sets it to NULL after the value was obtained. Then it creates NSData and NSNumber objects, adds those to NSArray objects and calls the obtained handler with those arrays.
So it seems that calling the method again just replaces the previous completionHandler which is never be called in that case. So you must not rely that a scheduled handler will eventually be called at some time in the future if the tunnel is not teared down if the possibility exists that your code might replace it. Also calling the method multiple times to schedule multiple callbacks has no effect as as only the last one will be kept and eventually be called.
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.
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];
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 know this question has been posted on this forum before:
How do you get the time interval for UIDatePicker in UIDatePickerModeCountDownTimer mode?
However, the answer mentioned there isnt working for me and i am not able to comment on the earlier post hence this new question.
I have a simple application where i have a UIDatePicker in CountDownTimer mode. I want to retrieve whatever value the user sets it to and store it or print it to log.
- (IBAction) datePickerValueDidChange:(id)sender {
NSLog(#"datePicker.countDownDuration: %f", timerPicker.countDownDuration);
}
the value being printed is 0 always. Dnt know where i am going wrong so any help will be appreciated.
You haven't posted much code, but my guess would be that your picker has a different name than timerPicker.
Alternately you've got a local instance variable conflict with your picker property and that referring to it as self.timerPicker.countDownDuration will do the trick.
A third option is that you've either not connected and/or declared your viewController as being the picker's delegate, or if you have then you haven't included the delegate declaration in your interface (though the latter is less likely because you should get a noticeable build-time error).
Otherwise you'll need to post some more code, including where you declare it and where you set its values.
Check this out, there is full tutorial about count down timer with date picker --- http://aarlangdi.blogspot.com.au hope this is helpful to you guys