how to use sortUsingFunction:context - iphone

appdata.items is NSMutableArray.
I connot compile This code.
Error code is "prop.173 has an incomplete type".
NSInteger compareInfo(id aInfo1, id aInfo2, void *context){
NSDate* info1 = [aInfo1 objectAtIndex:2];
NSDate* info2 = [aInfo2 objectAtIndex:2];
return [info1 compare:info2];
}
-(void)saveData{
NSData* data = [[NSMutableData alloc] init];
appdata.items = [appdata.items sortUsingFunction:compareInfo context:NULL];
NSKeyedArchiver* archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:appdata forKey:DATAKEY];
[archiver finishEncoding];
[data writeToFile:[self dataFilePath] atomically:YES];
[archiver release];
[data release];
}

Here is some code that might help you, (I spend pretty much time making it working, doc is not really helpfull)
It computes the distance between POI object and a currentLocation and order POI Object from the closest to the fartest from this location
NSInteger compareDistance(id num1, id num2, void *context)
{
int retour;
// fist we need to cast all the parameters
CLLocation* location = context;
POI* param1 = num1;
POI* param2 = num2;
// then we can use them as standard ObjC objects
CLLocation* locationCoordinates = [[CLLocation alloc] initWithLatitude:location.coordinate.latitude longitude:location.coordinate.longitude];
CLLocation* locationPOI1 = [[CLLocation alloc] initWithLatitude:param1.coords.latitude longitude:param1.coords.longitude];
CLLocation* locationPOI2 = [[CLLocation alloc] initWithLatitude:param2.coords.latitude longitude:param2.coords.longitude];
CLLocationDistance distance1 = [locationPOI1 distanceFromLocation:locationCoordinates];
CLLocationDistance distance2 = [locationPOI2 distanceFromLocation:locationCoordinates];
//make the comparaison
if (distance1 < distance2)
retour = NSOrderedAscending;
else if (distance1 > distance2)
retour = NSOrderedDescending;
else
retour = NSOrderedSame;
[locationCoordinates release];
[locationPOI1 release];
[locationPOI2 release];
return retour;
}
-(void) orderByProximityFromLocation:(CLLocationCoordinate2D) coordinates
{
CLLocation* currentLocation = [[CLLocation alloc] initWithLatitude:coordinates.latitude longitude:coordinates.longitude];
[listOfPOI sortUsingFunction:compareDistance context:currentLocation];
[currentLocation release];
}

The method sortUsingFunction:context: is for NSMutableArray, not NSArray, which sorts the contents of the mutable array. The method you want is sortedArrayUsingFunction:context: which will return a sorted array which you can assign, as you're currently trying to do.
Unless, of course, items is an NSMutableArray, in which case you can call sortUsingFunction:context: but as it doesn't return anything, so you don't assign it to items.

Related

How to add elements to an array created by a 'for' loop ?

I am using for loop for get distance from current location to destination location. I would like an array that contains all distances from current to destination location.
for (i = 0; i < [Arr_Lat count]; i++)
{
NSString *latst1 = [[NSString alloc]initWithFormat:[Arr_Lat objectAtIndex:i]];
NSString *longst1 = [[NSString alloc]initWithFormat:[Arr_Long objectAtIndex:i]];
NSLog(#"First lat : %#",latst1);
NSLog(#"First ong : %#",longst1);
double Doblat1 = [latst1 doubleValue];
double Doblong1 = [longst1 doubleValue];
CLLocationCoordinate2D coord1 = CLLocationCoordinate2DMake(coord1.latitude = Doblat1, coord1.longitude = Doblat1);
NSLog(#" Coordinat ==== : %f -- %f",coord1.latitude,coord1.longitude) ;
CLLocation *currLoc = [[CLLocation alloc] initWithLatitude:appDel.curr_lat longitude:appDel.curr_long];
CLLocation *destLoc1 = [[CLLocation alloc] initWithLatitude:Doblat1 longitude:Doblong1];
NSLog(#" Currennt Location : %#", currLoc);
NSLog(#" Destination Location : %#" , destLoc1);
distance = [destLoc1 distanceFromLocation:currLoc];
NSLog(#" Distance : ------- %0.3f", distance);
DistStr = [[NSString alloc]initWithFormat:#" %f",distance];
[currLoc release];
[destLoc1 release];
[Arr_title retain];
[tbl_nearplace reloadData];
}
If you want to store the distance you need an NSMutableArray.
Declare a NSMutableArray *distanceArray; in class scope.
Initialize it: distanceArray = [[NSMutableArray alloc] init];
In the for loop after DistStr =[[NSString alloc]initWithFormat:#" %f",distance];
write the following code:
[distanceArray addObject:DistStr];
Say we have this array with stuff we want to iterate over and add those items to another array
NSArray *someArrayWithStuff = #[#"Hello",
#"Its",
#"Very",
#"Cold",
#"Outside",
#"Today"];
Say we want the content of someArrayWithStuff to be added to this other array so we create an NSMutableArray
NSMutableArray *theNewArrayWithOurStuff = [NSMutableArray array];
We loop through the someArrayWithStuff
for (int i = 0; i < someArrayWithStuff.count; i++) {
// Add object to the new array
[theNewArrayWithOurStuff addObject:[someArrayWithStuff objectAtIndex:i]];
}
NSMutableArray *Distance=[[NSMutableArray alloc]Init];
for (i = 0; i < [Arr_Lat count]; i++)
{
NSString *latst1 = [[NSString alloc]initWithFormat:[Arr_Lat objectAtIndex:i]];
NSString *longst1 = [[NSString alloc]initWithFormat:[Arr_Long objectAtIndex:i]];
NSLog(#"First lat : %#",latst1);
NSLog(#"First ong : %#",longst1);
double Doblat1 = [latst1 doubleValue];
double Doblong1 = [longst1 doubleValue];
CLLocationCoordinate2D coord1 = CLLocationCoordinate2DMake(coord1.latitude = Doblat1, coord1.longitude = Doblat1);
NSLog(#" Coordinat ==== : %f -- %f",coord1.latitude,coord1.longitude) ;
CLLocation *currLoc = [[CLLocation alloc] initWithLatitude:appDel.curr_lat longitude:appDel.curr_long];
CLLocation *destLoc1 = [[CLLocation alloc] initWithLatitude:Doblat1 longitude:Doblong1];
NSLog(#" Currennt Location : %#", currLoc);
NSLog(#" Destination Location : %#" , destLoc1);
distance = [destLoc1 distanceFromLocation:currLoc];
NSLog(#" Distance : ------- %0.3f", distance);
NSString *DistStr = [[NSString alloc]initWithFormat:#" %f",distance];
[Distance addObject:DistStr];
[DistStr release];
[currLoc release];
[destLoc1 release];
[Arr_title retain];
[tbl_nearplace reloadData];
}

CLLocation causing EXC_BAD_ACCESS

This code works some of the time, but then sometimes crashes with a EXC_BAD_ACCESS error.
NSInteger compareDistance(id num1, id num2, void *context)
{
int rv;
//cast parameters from general type
CLLocation* location = (__bridge_transfer CLLocation *)context;
Attraction* attr1 = num1;
Attraction* attr2 = num2;
//convert to CLLocation objects and calculate distance from user current
CLLocation* locationAttr1 =
[[CLLocation alloc] initWithLatitude:attr1.latitude
longitude:attr1.longitude];
CLLocation* locationAttr2 =
[[CLLocation alloc] initWithLatitude:attr2.latitude
longitude:attr2.longitude];
CLLocationDistance distance1 = [locationAttr1 distanceFromLocation:location];
CLLocationDistance distance2 = [locationAttr2 distanceFromLocation:location];
//compare and rate
if (distance1 < distance2)
rv = NSOrderedAscending;
else if (distance1 > distance2)
rv = NSOrderedDescending;
else
rv = NSOrderedSame;
return rv;
}
This is a compare function for ordering an NSMutableArray:
-(NSMutableArray *)getAttractionsByDistanceInCategory:(int)catID
{
[self confirmAttractions];
//set up array and context to prepare for sort
NSMutableArray *attractionsToSort = [[NSMutableArray alloc] init];
for (Attraction *a in attractions)
{
if ((catID < 0) || (catID >= 0 && a.category == catID))
[attractionsToSort addObject:a];
}
CLLocation* currentLocation =
[[CLLocation alloc] initWithLatitude:usersLat longitude:usersLng];
//conduct sort
[attractionsToSort sortUsingFunction:compareDistance
context:(__bridge_retained void *)currentLocation];
return attractionsToSort;
}
Hmm. Do you think the problem could be ARC? I'm side-eyeing that __bridge_retained void * business.
Thanks in advance for any advice!
__bridge_transfer transfers ownership to the destination object, which is probably not what you want to do here, you don't want ownership of the context, because ARC will try and release it when it thinks you are done with it, and you don't want it to do that.
Basically, you don't want to transfer ownership anywhere, so just use __bridge in both cases, and it should work fine.

iPhone: Sorting based on location

I have been working on an iPhone app, where-in i have list of users in a NSMutableArray like below.
myMutableArray: (
{
FirstName = Getsy;
LastName = marie;
Latitude = "30.237314";
Longitude = "-92.461008";
},
{
FirstName = Angel;
LastName = openza;
Latitude = "30.260329";
Longitude = "-92.450414";
},
{
FirstName = Sara;
LastName = Hetzel;
Latitude = "30.2584499";
Longitude = "-92.4135357";
}
)
I need to sort users based on the location who is nearby to my location by calculating latitude and longitude. I am not able to achieve this till now. Could someone help me on giving some samples?
UPDATED: I am trying like below as per Mr.sch suggested. Please check my updated code. Is it fine?.
NSArray *orderedUsers = [myMutableArray sortedArrayUsingComparator:^(id a,id b) {
NSArray *userA = (NSArray *)a;
NSArray *userB = (NSArray *)b;
CGFloat aLatitude = [[userA valueForKey:#"Latitude"] floatValue];
CGFloat aLongitude = [[userA valueForKey:#"Longitude"] floatValue];
CLLocation *participantALocation = [[CLLocation alloc] initWithLatitude:aLatitude longitude:aLongitude];
CGFloat bLatitude = [[userA valueForKey:#"Latitude"] floatValue];
CGFloat bLongitude = [[userA valueForKey:#"Longitude"] floatValue];
CLLocation *participantBLocation = [[CLLocation alloc] initWithLatitude:bLatitude longitude:bLongitude];
CLLocation *myLocation = [[CLLocation alloc] initWithLatitude:locationCoordinates.latitude longitude:locationCoordinates.longitude];
CLLocationDistance distanceA = [participantALocation distanceFromLocation:myLocation];
CLLocationDistance distanceB = [participantBLocation distanceFromLocation:myLocation];
if (distanceA < distanceB) {
return NSOrderedAscending;
} else if (distanceA > distanceB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
Thank you!
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;
}
}];
First thing, you will need to calculate the distance between your current location and the location of each other user.
Talking mathematically, here is a Wolfram|Alpha example
Now "programmatic-ally", you can use CLLocation class, here is an example:
(CLLocationDistance)getDistanceFrom:(const CLLocation *)location
But first you will need to create the location object from your Latitude and Longitude. You can use:
(id)initWithLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude
You can calculate the distance (geographical, not flat plane!) between your position and each of these items' positions and order by that value.
- (void)viewDidLoad {
[super viewDidLoad];
// This Array Taken Globally
List_of_locationsArray =[[NSMutableArray alloc]initWithObjects:
#{#"latitude" : #"17.415045",#"logitude":#"78.421424"} ,#{#"latitude" : #"17.415045",#"logitude":#"78.421424"},#{#"latitude" : #"17.415045",#"logitude":#"78.421424"},#{#"latitude" : #"17.415045",#"logitude":#"78.421424"},#{#"latitude" : #"17.415045",#"logitude":#"78.421424"}
,nil];
}
-(void)sortingLocationsArray{
// CLLocation* currentLocation =[[CLLocation alloc]initWithLatitude:[currentLatitude doubleValue] longitude:[currentLogitude doubleValue]];
CLLocation* currentLocation =[[CLLocation alloc]initWithLatitude: currentLatitudeHere longitude:CurrentLogHere];
NSMutableArray* tempLocationsArr = [[NSMutableArray alloc]initWithCapacity:[locationsArray count]];
for (int i=0; i<[locationsArray count]; i++) {
CLLocationDegrees latValue = [[locationsArray[i] objectForKey:#"latitude"] doubleValue];
CLLocationDegrees longValue = [[locationsArray[i] objectForKey:#"logitude"] doubleValue];
CLLocation* location = [[CLLocation alloc]initWithLatitude:latValue longitude:longValue];
[tempLocationsArr addObject:location];
NSArray* sortLocationArry = [tempLocationsArr sortedArrayUsingComparator:^NSComparisonResult(CLLocation* location1, CLLocation* location2) {
CLLocationDistance distA = [location1 distanceFromLocation:currentLocation];
CLLocationDistance distB = [location2 distanceFromLocation:currentLocation];
if (distA < distB) {
return NSOrderedAscending;
} else if ( distA > distB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
//ArrayAfterSorting is another mutable Array to Store Sorting Data
[ArrayAfterSorting removeAllObjects];
[sortLocationArry enumerateObjectsUsingBlock:^(CLLocation* location, NSUInteger idx, BOOL *stop) {
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc]init];
[tempDict setObject:[NSString stringWithFormat:#"%f",location.coordinate.latitude] forKey:#"latitude"];
[tempDict setObject:[NSString stringWithFormat:#"%f",location.coordinate.longitude] forKey:#"logitude"];
[ArrayAfterSorting addObject:tempDict];
}];
NSLog(#"sortedArray : %#", ArrayAfterSorting);
}
}
You may solve your problem in following way
1)Firstly store all above values in separate array Like latArray ,longArray,nameArray
2)Now get the distance between location(longArray,latArray) from your current location.
Then store these distances in separate Array(distanceArray).
//getDistance Between currentLocation and desired Location
-(void *)getDistanceFromCurrentLocation{
for(int val=0;val<[latArray count];val++){
NSString *dis_From_Current_Location;
dis_From_Current_Location =nil;
CGFloat str_Longitude=[[defaults objectForKey:#"long"]floatValue];
CGFloat str_Latitude=[[defaults objectForKey:#"lati"]floatValue];
//Suppose this is your current location
CGFloat lat1= [[latArray objectAtIndex:val]floatValue];
//these array for lat
CGFloat long1=[[longArray objectAtIndex:val]floatValue];
//these array for longArray
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:lat1 longitude:long1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:str_Latitude longitude:str_Longitude];
CLLocationDistance dist=[location1 distanceFromLocation:location2];
NSLog(#"Distance i meters: %f", [location1 distanceFromLocation:location2]);
long long v = llabs(dist/1000);
dis_From_Current_Location=[NSString stringWithFormat:#"%lld km",v];
[location1 release];
[location2 release];
[distanceArray addObject: dis_From_Current_Location];
//distanceArray is Global NsMutableArray.
}
}
Now You should Apply sorting method(selection, bubble) fro sorting the distances.
One thing need to care is that when you sort the distanceArray
please adjust values of nameArray as according to the distanceArray
See Below code for sorting the distanceArray and adjust the nameArray's value.
-(void)getSoretdArray{
NSString * tempStr,*tempStr2;
for(int i=0;i<[distanceArray count]; i++){
for(int j=i+1;j<[distanceArray count]; j++){
if([distanceArray objectAtIndex:j]>[distanceArray objectAtIndex:j+1]){
tempStr=[distanceArray objectAtIndex:j];
NSString* str= [distanceArray objectAtIndex:j+1];
[ distanceArray insertObject:str atIndex:j];
[distanceArray insertObject:tempStr atIndex:j+1] ;
//also change the name of corresponding location.
//you have to adjust the stored names in namArray for storing names of Corresponding Distances
tempStr2=[nameArray objectAtIndex:j];
NSString* str1= [nameArray objectAtIndex:j+1];
[ nameArray insertObject:str1 atIndex:j];
[nameArray insertObject:tempStr2 atIndex:j+1] ;
}
}
}
}
This will definitely work just try to use carefully

How to solve Memory leaks for following Sqlite code?

I am getting memory leaks in Instruments in the following Sqlite Code.
NSArray *result = [self executeQuery:sql arguments:argsArray];
It calls following method.
- (NSArray *)executeQuery:(NSString *)sql arguments:(NSArray *)args {
sqlite3_stmt *sqlStmt;
if (![self prepareSql:sql inStatament:(&sqlStmt)])
return nil;
int i = 0;
int queryParamCount = sqlite3_bind_parameter_count(sqlStmt);
while (i++ < queryParamCount)
[self bindObject:[args objectAtIndex:(i - 1)] toColumn:i inStatament:sqlStmt];
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
int columnCount = sqlite3_column_count(sqlStmt);
while ([self hasData:sqlStmt]) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (i = 0; i < columnCount; ++i) {
id columnName = [self columnName:sqlStmt columnIndex:i];
id columnData = [self columnData:sqlStmt columnIndex:i];
[dictionary setObject:columnData forKey:columnName];
}
[arrayList addObject:[dictionary autorelease]];
}
sqlite3_finalize(sqlStmt);
return arrayList;
}
How do I solve it ?
We'd need to see the code of your executeQuery method - it should be returning an auto-released result, but perhaps it isn't.
You could try ;
NSArray *result = [[self executeQuery:sql arguments:argsArray] autorelease];
But I'd be wary of just blindly trying that without actually seeing what executeQuery does in detail.
EDIT:
OK, here's your problem;
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
Either create it as an auto-released array, or finish the method with;
return [arrayList autorelease];

NSString: fastes way of splitting

my question is a performance question.
I need to split a huge NSString into coordinates. The string has this format:
#"coordx,coordy coordx,coordy coordx,coordy (...)"
My method to parse this is:
-(NSMutableArray*) parsePath:(NSString*) pathString
{
// first split between the coordinates
NSArray* path = [pathString componentsSeparatedByString:#" "];
NSMutableArray* coords = [[NSMutableArray alloc] init];
static NSString *seperator = #",";
NSArray *coord;
for(NSString *coordString in path)
{
coord = [coordString componentsSeparatedByString:seperator];
Coordinate *c = [[Coordinate alloc]init];
c.x = [[coord objectAtIndex:0] intValue];
c.y = [[coord objectAtIndex:1] intValue];
[coords addObject:c];
[c release];
}
return coords;
}
So, is there any way to make this faster?
Thanks!
Sebastian
Using NSScanner is probably faster.
http://developer.apple.com/iphone/library/documentation/cocoa/reference/Foundation/Classes/NSScanner_Class/Reference/Reference.html