I have developer an walk app that can record distance, on ios7,ios8,the distance almost fine although some time not accurate,but on ios9.0, the distance often too larger, so I check
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)
Locations method, and find some time timestamp of new location early than some previous location, it means location from callBack are not sorted by timestamp, why is that and how deal with it,
Thanks in advance
after many try, I found call startUpdatingLocation in a period timer cause CLLocation returned by delegate often wrong, I think that's the problem
Related
I learned objective c myself and haven't taken any courses for it. Hence, some times I get confused with minor things while writing iOS app. This question may be very lame, but I could not find any solution or I could not understand the solution. Here is my situation:
My app contains single view controller (the default one). I want to get continuous values from accelerometer, gyroscope and magnetometer and use the values to estimate user location using pedestrian dead reckoning (PDR). For this purpose, I used CoreMotion and made a CLMotionManager (motionManager) property in header file. Using this manager, I can check whether the sensors are available and get their values, for example:
if([_motionManager isAccelerometerAvailable])
{
_motionManager.accelerometerUpdateInterval = 0.1;
[_motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc]init] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
x=accelerometerData.acceleration.x;
y = accelerometerData.acceleration.y;
z = accelerometerData.acceleration.z;
}];}
Similarly, I can get values from gyroscope and magnetometer. I get these values inside a IBAction method after pressing a button as:
-(IBAction)startSensor:(id)sender
{
//Getting accelerometer, gyroscope, and magnetometer values.
}
The PDR operation happens in my next method as:
-(void)thePDROperationWith:(NSArray*)accelerometerValues gyroscopeValues:(NSArray*)gyros magnetometerValues:(NSArray*)magneto
{
//The PDR operations with accelerometer, gyroscope and magnetometer values
}
Now, my question is:
1) How to get continuous PDR operation value from thePDROperationWith::
method? I called this method inside the startSensor method, however I
get the value just once when I press the button. Moreover, am I supposed
to declare this method in header file too (as in user defined NSObject subclass)?
2) What is the difference between user defined method and delegate methods like
//a method in CLBeaconManager delegate
-(void)beaconManager:(CLBeaconManager*)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
//code
} ?
This delegate method (I expect I am using the correct term) runs continuously to range the beacons in the defined CLBeaconRegion. How can I make such method for my purpose?
Thank you.
startAccelerometerUpdatesToQueue does what the name says — it begins a sequence of accelerometer update methods, and communicates them to you on the nominated queue, which in your case is an arbitrary background queue.
Therefore the code where you currently store values to x, y and z will be performed every time the OS spots a change in the accelerometer. You've likely got a similar sequence of perpetual updates coming from the gyroscope and magnetometer.
So those streams of information can be the triggers for your updates. Each time a new accelerometer, gyroscope or magnetometer update arrives, update your knowledge.
(Quick aside warning though: if you're creating a separate queue for each of those three things then it's likely you'll end up servicing them on different threads. So you'll need to worry about concurrent data access. Or you could instead use [NSOperationQueue mainQueue] to have all updates received on the same queue, which is also the one that UIKit operates on, if you just wanted the OS to serialise everything for you).
A delegate method is one that represents a function that one class delegates to another. In this case the beacon manager knows how to track beacons, but not what's appropriate in this application to do as a result of tracked beacons. So it delegates the decisions that flow from beacon changes.
Objective-C lets you be really loose about these things so you might see some very informal approaches if looking at older code, but the normal way nowadays is to declare a delegate protocol, e.g.:
#class MyClass; // Declare that there is a class called MyClass.
// Define a protocol for delegates.
#protocol MyProtocol
- (void)thisClass:(MyClass *)class learntFact:(Fact *)fact;
#end
// Here's MyClass for real
#interface MyClass
#property(nonatomic, weak) id<MyProtocol> factDelegate;
#end
Then when an instance of MyClass has something to say it just tells the delegate:
[self.factDelegate thisClass:self learntFact:...fact here...];
And somebody that wants to be a delegate sets instanceOfMyClass.factDelegate = self, having announced support for the relevant protocol.
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 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.