We are building location based reminder app and it works in 7 case out of 10. It simply misses certain locations. Can you please suggest what would be the possible issue with that?
Following is the logic we are using for location matching.
-(void)locationChangeLogic {
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:latitudeTemp longitude:longitudeTemp];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Perform long running process
NSArray *arrayLocations = [[NSArray alloc] initWithArray:[[self db] getListOfLocations]];
NSMutableArray *arrayToNotification = [[NSMutableArray alloc] init];
if ([arrayLocations count] > 0) {
for (NSDictionary *dict in arrayLocations) {
CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:[[dict valueForKey:#"latitude"] floatValue] longitude:[[dict valueForKey:#"longitude"] floatValue]];
float miles = [[NSUserDefaults standardUserDefaults] floatForKey:#"miles"];
CLLocationDistance distance = [currentLocation distanceFromLocation:newLocation];
//Set matched objects and update flag
if ((distance/1609.344) <= miles) {
if ([[dict valueForKey:#"isSelected"] integerValue] == 1) {
[arrayToNotification addObject:dict];
}
//Matched location FLAG will going to 0, so notification not get fire twice or repeatedly
}else {
//The location which are not in current redius, we will make those location FLAG to 1, So when user enter in different location it will check for that
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
if ([arrayToNotification count] > 0) {
[self setAndFireLocalNotifications:arrayToNotification];
}
});
});
}
Any help would be appreciated.
Related
User has to create his own path on google map wherever he move step by step the route is generated.
please have look on my code snippet:
- (void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations
{
CLLocation* location1 = [locations lastObject];
if (self.endPointArray == nil)
{
self.endPointArray = [[NSMutableArray alloc]init];
}
NSString *pointString=[NSString stringWithFormat:#"%f,%f",location1.coordinate.latitude,location1.coordinate.longitude];
[self.endPointArray addObject:pointString];
NSLog(#"end point array :%#",self.endPointArray);
GMSMutablePath *path = [GMSMutablePath path];
for (int i=0; i<self.endPointArray.count; i++)
{
NSArray *latlongArray = [[self.endPointArray objectAtIndex:i]componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
[path addLatitude:[[latlongArray objectAtIndex:0] doubleValue] longitude:[[latlongArray objectAtIndex:1] doubleValue]];
}
if (self.endPointArray.count>2)
{
GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
polyline.strokeColor = [UIColor redColor];
polyline.strokeWidth = 3.0f;
polyline.map = _mapView;
}
}
I have create route with help of above code.but sometimes we get unexpected coordinates from CLLocation. If we are on road (route) it's gives perfect but if we are not on road like in home it gives wrong coordinates
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
NSTimeInterval age = -[location.timestamp timeIntervalSinceNow];
if (age > 120) return; // ignore old (cached) updates
if (location.horizontalAccuracy < 0) return; // ignore invalid updates
if(self.oldLocation == nil)
{
self.oldLocation = location;
return
}
CLLocationDistance distance = [location distanceFromLocation: self.oldLocation];
if (distance >= 10 && location.horizontalAccuracy <=20) //you can change 10 to 20 if you want more frequent updates
{
// add location to path
self.oldLocation = location; // save newLocation for next time
}
}
Try using this code. Its from my project and it works just fine. Use it according to your need. Hope it helps you.
I've an NSArray containing users information of their places, i.e their latitude and longitudes.
I also got the current user's location, now I want to sort out the list of latitudes and longitudes from the NSArray so that the current user can see his nearby users easily.
For instance, I've the following information.
NSArray *ALLINFOLAT = [ALLINFO valueForKey:#"lat"]
// having "40.880048", "40.749315", "40.749278",
NSArray *ALLINFOLNG = [ALLINFO valueForKey:#"lng"]
// having "-77.145461", "-122.258591", "-122.320566"
NSString *currentUserLat = #"78";
NSString *currentUserLng = #"87";
How can I sort out the NSDictionary ALLINFO according to currentUserLat & currentUserLng using NSSortDescriptor.
I think you are confusing people by creating separate arrays for latitude and longitude.
If I understand correctly, you have an array ALLINFO that hold informations about users and their location, and you want to sort it based on distance to the current location.
You didn't specified what objects you have in array, so I assume they are dictionaries.
Here's how you get a sorted array:
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude: 78 longitude: 87];
NSArray *orderedInfo = [ALLINFO sortedArrayUsingComparator: ^(NSDictionary *object1, NSDictionary *object2)
{
CLLocation *location1 = [[CLLocation alloc] initWithLatitude: [object1[#"lat"] doubleValue] longitude: [object1[#"lng"] doubleValue]];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude: [object2[#"lat"] doubleValue] longitude: [object2[#"lng"] doubleValue]];
CLLocationDistance dist1 = [location1 distanceFromLocation:currentLocation];
CLLocationDistance dist2 = [location2 distanceFromLocation:currentLocation];
if (dist1 < dist2) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( dist1 > dist2) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}];
NSMutableArray *ALLINFOLAT =#[#(40.880048), #(40.749315), #(40.749278)];
NSMutableArray *ALLINFOLNG =#[#(-77.145461), #(-122.258591), #(-122.320566)];
NSString *currentUserLat = #"78";
NSString *currentUserLng = #"87";
CLLocation* currentLocation =[[CLLocation alloc]initWithLatitude:[currentUserLat doubleValue] longitude:[currentUserLng doubleValue]];
NSMutableArray* locationArray = [[NSMutableArray alloc]initWithCapacity:[ALLINFOLNG count]];
for (int i=0; i<[ALLINFOLAT count]; i++) {
CLLocationDegrees latValue = [ALLINFOLAT[i] doubleValue];
CLLocationDegrees longValue = [ALLINFOLNG[i] doubleValue];
CLLocation* location = [[CLLocation alloc]initWithLatitude:latValue longitude:longValue];
[locationArray addObject:location];
}
NSArray* sortLocationArry = [locationArray sortedArrayUsingComparator:^NSComparisonResult(CLLocation* location1, CLLocation* location2) {
CLLocationDistance distA = [location1 distanceFromLocation:currentLocation];
CLLocationDistance distB = [location2 distanceFromLocation:currentLocation];
if (distA < distB) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( distA > distB) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}];
To get sorted latitude and longitude,
[ALLINFOLAT removeAllObjects];
[ALLINFOLNG removeAllObjects];
[sortLocationArry enumerateObjectsUsingBlock:^(CLLocation* location, NSUInteger idx, BOOL *stop) {
[ALLINFOLAT addObject:#(location.coordinate.latitude)];
[ALLINFOLNG addObject:#(location.coordinate.longitude)];
}];
Following is the code for the sort by the location long/lati.
NSArray *orderedUsers = [users sortedArrayUsingComparator:^(id a,id b) {
User *userA = (User *)a;
User *userB = (User *)b;
CLLocationDistance distanceA = [userA.location getDistanceFromLocation:myLocation];
CLLocationDistance distanceB = [userB.location getDistanceFromLocation:myLocation];
if (distanceA < distanceB) {
return NSOrderedAscending
} else if (distanceA > distanceB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
--------EDITED--------
Following code for just pass the value of your long/lati only.
NSArray *orderedUsers = [self.shopsArray sortedArrayUsingComparator: ^(double aLong, double bLong,double aLati, double bLati)
{
CLLocation *usersA = [[CLLocation alloc] initWithLatitude: aLati longitude: bLati];
CLLocation *usersB = [[CLLocation alloc] initWithLatitude: aLong longitude: bLong];
CLLocationDistance distA = [usersA distanceFromLocation:currentLocation];
CLLocationDistance distB = [usersB distanceFromLocation:currentLocation];
if (distA < distB) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( distA > distB) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}];
May this help to you.
How can i sort the array based on distance from current location and show in tableview .when i use below code for sorting am not getting any proper results ,am getting the array with random distance.can any one guide me for solve this issue
-(void)sort_distance{
// Determine distance between current location and geofence location
[distance_array removeAllObjects];
NSMutableDictionary *dict=[[NSMutableDictionary alloc] init];
CLLocation *pinLocation;
CLLocation *userLocation;
for (int i=0; i<[self.geofences count]; i++) {
//dict =[self.geofences objectAtIndex:i];
CLLocationDegrees firstLat = [self.currentLatitude doubleValue];
CLLocationDegrees firstLong = [self.currentLongitude doubleValue];
CLLocationDegrees secondLat = [[[self.geofences objectAtIndex:i] objectForKey:#"lat"] doubleValue];
CLLocationDegrees secondLong = [[[self.geofences objectAtIndex:i] objectForKey:#"lon"] doubleValue];
pinLocation = [[CLLocation alloc]
initWithLatitude:secondLat
longitude:secondLong];
userLocation = [[CLLocation alloc]
initWithLatitude:firstLat
longitude:firstLong];
CLLocationDistance distance = [pinLocation distanceFromLocation:userLocation]/1000;
//current distance is NSNumber
CLLocationDistance kilometers = distance /1000;
// or you can also use this..
distanceString = [[NSString alloc] initWithFormat: #"%.1f Km", kilometers];
NSLog(#"sa: %#", distanceString);
[distance_array addObject:distanceString];
[dict setObject:[NSNumber numberWithDouble:distance] forKey:#"newdistance"];
}
NSLog(#"distance array: %#", distance_array);
// Sorting the Geofence-Location depends on distance from current location
NSSortDescriptor * sort = [[NSSortDescriptor alloc] initWithKey:#"newdistance" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sort];
sortedArray = [self.geofences sortedArrayUsingDescriptors:sortDescriptors];
}
My out put is
distance array: (
"0.2 Km",
"0.4 Km",
"0.2 Km",
"0.6 Km",
"0.7 Km",
"1.0 Km",
"0.3 Km"
)
Thanks in Advance,
Chandu.
-(void)sort_distance{
// Determine distance between current location and geofence location
[distance_array removeAllObjects];
NSMutableDictionary *dict=[[NSMutableDictionary alloc] init];
CLLocation *pinLocation;
CLLocation *userLocation;
for (int i=0; i<[self.geofences count]; i++) {
//dict =[self.geofences objectAtIndex:i];
CLLocationDegrees firstLat = [self.currentLatitude doubleValue];
CLLocationDegrees firstLong = [self.currentLongitude doubleValue];
CLLocationDegrees secondLat = [[[self.geofences objectAtIndex:i] objectForKey:#"lat"] doubleValue];
CLLocationDegrees secondLong = [[[self.geofences objectAtIndex:i] objectForKey:#"lon"] doubleValue];
pinLocation = [[CLLocation alloc]
initWithLatitude:secondLat
longitude:secondLong];
userLocation = [[CLLocation alloc]
initWithLatitude:firstLat
longitude:firstLong];
CLLocationDistance distance = [pinLocation distanceFromLocation:userLocation]/1000;
//current distance is NSNumber
CLLocationDistance kilometers = distance /1000;
// or you can also use this..
distanceString = [[NSString alloc] initWithFormat: #"%.1f km", kilometers];
NSLog(#"sa: %#", distanceString);
[distance_array addObject:distanceString];
[dict setObject:[NSNumber numberWithDouble:distance] forKey:#"newdistance"];
}
NSLog(#"distance array: %#", distance_array);
// Sorting the Geofence-Location depends on distance from current location
sortedArray = [distance_array sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"%#",sortedArray);
}
CLLocationDistance is double type, while you are saving it as integer type. So you will loose some precision. Instead use `[NSNumber numberWithDouble:].
This will sort in ascending order, for descending order return NSOrderedAscending in place of NSOrderedDescending and vice-versa.
-(CLLocationDistance )distanceOfCurrentPosition:(CLLocation *)userLocation WithPosition:(NSDictionary *)postition{
CLLocationDegrees secondLat = [postition[#"lat"] doubleValue];
CLLocationDegrees secondLong = [postition[#"lon"] doubleValue];
CLLocation *pinLocation = [[CLLocation alloc]
initWithLatitude:secondLat
longitude:secondLong];
CLLocationDistance distance = [pinLocation distanceFromLocation:userLocation]/1000;
CLLocationDistance kilometers = distance /1000;
return kilometers;
}
-(void)sort_distance{
CLLocationDegrees firstLat = [self.currentLatitude doubleValue];
CLLocationDegrees firstLong = [self.currentLongitude doubleValue];
CLLocation *userLocation = [[CLLocation alloc]
initWithLatitude:firstLat
longitude:firstLong];
[_geofences sortUsingComparator:^NSComparisonResult(NSDictionary *position1, NSDictionary *position2) {
CLLocationDistance distanceWithPosition1 = [self distanceOfCurrentPosition:userLocation WithPosition:position1];
CLLocationDistance distanceWithPosition2 = [self distanceOfCurrentPosition:userLocation WithPosition:position2];
if (distanceWithPosition1> distanceWithPosition2) {
return NSOrderedDescending;
}else if(distanceWithPosition2 > distanceWithPosition1){
return NSOrderedAscending;
}else{
return NSOrderedSame;
}
}];
NSLog(#"Order :%#",_geofences);
}
Try these for sort your array
-(NSArray *)sortArray:(NSArray *)arrayForSort forKey:(NSString *)key
{
return [arrayForSort sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if([obj1 isKindOfClass:[NSDictionary class]] && [obj2 isKindOfClass:[NSDictionary class]])
return [[obj1 objectForKey:key] compare:[obj2 objectForKey:key]];
return NSOrderedSame;
}];
}
Just call it your case
self.geofences = [self sortArray:self.geofences forKey:#"newdistance"];
Have a nice day :)
I have been working to implement route trace map for walking,biking and driving.
However, as you see in the following screenshot, my coordinate jumps all of a sudden from time to time even though I did not walk/bike or drive that location. The circle has been drawn on the image to point out the problem. My question is why all of a sudden coordinates jumps ?
Here is my implementation snapshot:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
CoordinateModel *coord = [[CoordinateModel alloc] init];
coord.latitude = newLocation.coordinate.latitude;
coord.longitude = newLocation.coordinate.longitude;
ActivityType currentActivityType = [DataManager sharedInstance].activityType;
if (currentActivityType == 0) {
// walking
[appDelegate.walkingCoordinates addObject:coord];
}
else if(currentActivityType == 1) {
[appDelegate.bikingCoordinates addObject:coord];
}
else if(currentActivityType == 2) {
// driving
[appDelegate.drivingCoordinates addObject:coord];
}
self.coordinate = newLocation.coordinate;
}
I suggest you not to use the delegate method locationManager:didUpdateToLocation:fromLocation: anymore and it has been deprecated.
You should use locationManager:didUpdateLocations instead.
About your question, the location "jumping" like you mention is due to the GPS that is unable to determine the accuracy of your location during a certain time. If you record down the coordinate and also the accuracy for all the time including when you are indoor, you will realize that the accuracy when you are staying indoor is not good, you might see the accuracy 1414 when you are connected to Wifi. GPS does not work well when you are indoor. So, your code has to be smart enough to only draw a path or send the coordinate to the server when only the coordinate is good enough.
The below code are some of the criteria that I use to filter out the bad coordinates.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
for(int i=0;i<locations.count;i++){
CLLocation * newLocation = [locations objectAtIndex:i];
CLLocationCoordinate2D theLocation = newLocation.coordinate;
CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 30.0)
continue;
//Select only valid location and also location with good accuracy
if(newLocation!=nil&&theAccuracy>0
&&theAccuracy<2000
&&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){
self.myLastLocation = theLocation;
self.myLastLocationAccuracy= theAccuracy;
NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
[dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:#"latitude"];
[dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:#"longitude"];
[dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:#"theAccuracy"];
//Add the valid location with good accuracy into an array
//Every 1 minute, I will select the best location based on accuracy and send to server
[self.shareModel.myLocationArray addObject:dict];
}
}
}
After a certain period (eg: 3 minutes), I will again choose the best coordinate from self.shareModel.myLocationArray before drawing the coordinate on map and send the coordinate to the server.
You may see the full solution and sample project from here: Background Location Services not working in iOS 7
Don't forget to upvote if my answer is good enough. ;)
Same Problem has been still in the code.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
iNEAT_o_GamesAppDelegate *appDelegate = (iNEAT_o_GamesAppDelegate *)[[UIApplication sharedApplication] delegate];
CoordinateModel *coord = [[CoordinateModel alloc] init];
ActivityType currentActivityType = [DataManager sharedInstance].activityType;
for(int i=0;i<locations.count;i++){
CLLocation * newLocation = [locations objectAtIndex:i];
CLLocationCoordinate2D theLocation = newLocation.coordinate;
CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 30.0)
continue;
//Select only valid location and also location with good accuracy
if(newLocation!=nil&&theAccuracy>0
&&theAccuracy<2000
&&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){
coord.latitude = theLocation.latitude;
coord.longitude = theLocation.longitude;
if (currentActivityType == 0) {
// walking
[appDelegate.walkingCoordinates addObject:coord];
}
else if(currentActivityType == 1) {
[appDelegate.bikingCoordinates addObject:coord];
}
else if(currentActivityType == 2) {
// driving
[appDelegate.drivingCoordinates addObject:coord];
}
}
}
}
I'm trying to loop through an array of about 10 latitude and longitude values and get the address from them. I created a console application using Xcode and I'm able to loop the file and retrieve the locations, add them to an NSMutableArray and pass it to the below function. However the completion handler block never gets called. What could I be doing wrong? Let me know if you need to see any other code at this point. I'm just frustrated and confused and wonder what could it be.
void nextGeocodeRequest(int start, NSMutableArray * myLocations)
{
#autoreleasepool {
for (int i = start; i < 1; i++) {
[ myLocations objectAtIndex:i ];
double mylong = [[[myLocations objectAtIndex:i] valueForKey:#"Longitude"] doubleValue ];
double mylat = [[[myLocations objectAtIndex:i] valueForKey:#"Latitude"] doubleValue];
goal = [[CLLocation alloc] initWithLatitude: mylat longitude:mylong] ;
CLGeocoder * geocoder = [[CLGeocoder alloc]init];
[geocoder reverseGeocodeLocation:goal completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
NSLog(#"this is the state '%#'",placemark.locality);
/*
self.state = [[State alloc] init];
self.state.name = placemark.locality;
self.state.code = placemark.administrativeArea;
self.state.stateId = 1;
self.state.stations = 300;
[self.states addObject:self.state];
*/
//[self.tableView reloadData];
nextGeocodeRequest(i, myLocations);
} else {
NSLog(#"%#", error.debugDescription);
}
}];
} //ends the for
// return 0;
}
}
You need to run the current NSRunLoop at the end of your main function such that the geocoding connections will be processed. You then need to define how your app will terminate after all of the connections are processed.
[[NSRunLoop currentRunLoop] run];
(put this at the end of the auto release pool in your main function)
Currently your app does all of the inline processing, prepares a number of connections with nothing to process them and then simply exits.