I have this code where I use NSMutableArray to parse a csv file. There are no errors that stop me from running the app however the map doesn't display anything.
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data2" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSMutableArray *allLinedStrings = [[NSMutableArray alloc]initWithArray:[dataStr componentsSeparatedByString:#"\r"]];
NSMutableArray *latitude = [[NSMutableArray alloc]init];
NSMutableArray *longitude = [[NSMutableArray alloc]init];
NSMutableArray *description = [[NSMutableArray alloc]init];
NSMutableArray *address = [[NSMutableArray alloc]init];
NSMutableArray *temperature = [[NSMutableArray alloc]init];
NSMutableArray *time = [[NSMutableArray alloc]init];
NSMutableArray *ambient = [[NSMutableArray alloc]init];
NSMutableArray *filteredLocations = [NSMutableArray array];
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * filteredLocations.count);
for (int idx = 0; idx < [allLinedStrings count]; idx++)
{
NSMutableArray *infos = [[NSMutableArray alloc]initWithArray:[[allLinedStrings objectAtIndex:idx] componentsSeparatedByString:#","]];
if ([infos count] > 1)
{
[latitude addObject:[infos objectAtIndex:4]];
[longitude addObject:[infos objectAtIndex:5]];
[description addObject:[infos objectAtIndex:0]];
[address addObject:[infos objectAtIndex:10]];
[temperature addObject:[infos objectAtIndex:6]];
[time addObject:[infos objectAtIndex:15]];
[ambient addObject:[infos objectAtIndex:8]];
if([[latitude objectAtIndex:4] isEqualToString:#"NULL"] || [[longitude objectAtIndex:5] isEqualToString:#"NULL"] || [[description objectAtIndex:0] isEqualToString:#"NULL"] || [[address objectAtIndex:10]isEqualToString:#"NULL"] || [[temperature objectAtIndex:6] isEqualToString:#"NULL"] || [[time objectAtIndex:15]isEqualToString:#"NULL"] || [[ambient objectAtIndex:8] isEqualToString:#"NULL"]) {continue;}
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[latitude objectAtIndex:4] doubleValue];
coordinate.longitude = [[longitude objectAtIndex:5] doubleValue];
Location *annotation = [[Location alloc] initWithName:[description objectAtIndex:0] address:[address objectAtIndex:10] temperature:[temperature objectAtIndex:6] time:[time objectAtIndex:15] ambient:[ambient objectAtIndex:8] coordinate:coordinate] ;
[mapview addAnnotation:annotation];
[filteredLocations addObject:annotation];
MKMapPoint point = MKMapPointForCoordinate(coordinate);
pointArr[idx] = point;
}
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:filteredLocations.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapview.annotations)
{
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
[mapview setVisibleMapRect:zoomRect animated:YES];
self.mapview.delegate = self;
}
I guess there must be something wrong with how I'm calling the objects or maybe the MKMapPoint but I don't manage to find what's blocking the app from displaying the data. I've tried using both "initWithObjects" and removing "if ([infos count] > 1){" but when ran it crashed showing a breakdown point in "NSMutableArray *latitude = [[NSMutableArray alloc]init];".
Based on your previous questions about this project, you want to do the following at a high level:
Parse a CSV file where each line has coordinate data. Ignore lines that have "null" data. (For the purpose of this answer, let's ignore that one could use a pre-built CSV parser, or use a different format altogether.)
Show annotations for lines with "good" data.
Connect all the annotations with a line.
For requirement 1 (R1), you already know how to load the CSV file, loop through the lines, and identify the lines with "null" data.
For requirement 2 (R2), after some research, you know that you can create and add annotations to the map one at a time and the map doesn't need to know ahead of time how many you will add so that means the first two requirements could be done in the same loop.
For requirement 3 (R3), after some research, you know that to create and add a polyline to the map, you need to know ahead of time how many points will be in the line.
For R1 and R2, you will be looping through the lines of the CSV and identify the non-null lines.
So that means you will know how many points will be in the polyline after the loop that handles R1 and R2. That means the polyline must be created after that loop.
But to create the polyline, you need not just the point count but the coordinates for each point as well.
That means while looping through the lines in the CSV, you need to save the coordinate data somewhere (in the same order it appeared in the CSV).
In Objective-C, a convenient structure that allows you to add data to it without knowing in advance how many objects will be added is an NSMutableArray.
So now we have this very high-level plan:
Loop through the CSV file, ignore lines with null data, create and add annotations, add the line data to an NSMutableArray (NSMA).
Create a polyline using the point data in NSMA, add the polyline to the map.
With this plan, we see we need one NSMutableArray. Notice that in the existing code, you have a Location class that holds (or could hold) all the data from each line of the CSV.
That means we could simply add these Location objects to the NSMA. NSMutableArrays can hold any type of object (they don't have to be just NSStrings).
So here's a slightly more detailed plan:
Initialize an NSMutableArray called filteredLocations (eg. NSMutableArray *filteredLocations = [NSMutableArray array];).
Loop through the CSV file, ignore lines with null data, create a Location object and add as an annotation, add the Location object to filteredLocations (eg. [filteredLocations addObject:annotation];).
Initialize (malloc) a C array to hold the points of the polyline with the point count being the count of filteredLocations.
Loop through filteredLocations, add point from filteredLocations to the C array.
Create and add a polyline to the map.
In this plan note we have two separate loops: The first one is for R1 and R2. The second one is for R3.
If required, I will post sample code that implements this plan.
First, just to explain your latest NSRangeException error, it is happening on this line:
if([[latitude objectAtIndex:4] isEqualToString:#"NULL"] || ...
because you've declared latitude as an array and the first time the if executes in the loop, latitude only has one object (a few lines above this if you do [latitude addObject:...). The index of an array starts at zero so the bounds of an array with one object are zero to zero hence the error message saying index 4 beyond bounds [0 .. 0].
There are many other issues with the rest of the code.
There is not enough room in this answer to explain in detail.
I urge you, if possible, to stop, step back and re-start with a much simpler project or tutorials and, most importantly, learn the absolute basics of programming in general.
Here is an example of code that should work based on your sample data:
-(void)viewDidLoad
{
[super viewDidLoad];
self.mapview.delegate = self;
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data2" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSArray *allLinedStrings = [dataStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableArray *filteredLocations = [NSMutableArray array];
for (int idx = 0; idx < [allLinedStrings count]; idx++)
{
NSArray *infos = [[allLinedStrings objectAtIndex:idx] componentsSeparatedByString:#","];
if ([infos count] > 15)
{
NSString *latitude = [infos objectAtIndex:4];
NSString *longitude = [infos objectAtIndex:5];
NSString *description = [infos objectAtIndex:0];
NSString *address = [infos objectAtIndex:10];
NSString *temperature = [infos objectAtIndex:6];
NSString *time = [infos objectAtIndex:15];
NSString *ambient = [infos objectAtIndex:8];
if([latitude isEqualToString:#"NULL"]
|| [longitude isEqualToString:#"NULL"]
|| [description isEqualToString:#"NULL"]
|| [address isEqualToString:#"NULL"]
|| [temperature isEqualToString:#"NULL"]
|| [time isEqualToString:#"NULL"]
|| [ambient isEqualToString:#"NULL"])
{
continue;
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = [latitude doubleValue];
coordinate.longitude = [longitude doubleValue];
Location *annotation = [[Location alloc] initWithName:description
address:address
temperature:temperature
time:time
ambient:ambient
coordinate:coordinate];
[mapview addAnnotation:annotation];
[filteredLocations addObject:annotation];
}
}
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * filteredLocations.count);
for (int flIndex = 0; flIndex < filteredLocations.count; flIndex++)
{
Location *location = [filteredLocations objectAtIndex:flIndex];
MKMapPoint point = MKMapPointForCoordinate(location.coordinate);
pointArr[flIndex] = point;
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:filteredLocations.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
[self.mapview showAnnotations:self.mapview.annotations animated:YES];
}
I am parsing a CSV file multiple times with for loop, here I need to store these arrays one by one dictionary. There are very less questions in stack about adding NSArray to NSDictionary. I am parsing CSV with below code but I strucked at storing in NSDictionary, The program is terminating and showing warning at assigning string to dictionary
for (i=0; i<=57; i++) {
NSString *keysString = [csvArray objectAtIndex:i];
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
NSLog(#"Serail No %d %#",i,keysArray);
NSString *string = [NSString stringWithFormat:#"%d", i];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjects: keysArray forKeys: string];
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
for (i=0; i<=57; i++) {
NSString *keysString = [csvArray objectAtIndex:i];
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
NSString *key = [NSString stringWithFormat:#"serial%d",i];
[dict setObject:keysArray forKey:key];
}
To get back data from dictionary,
NSArray *array = [dict valueForKey:#"serial24"];//to get array 24.
If I understand you correctly, you want to add the arrays to a dictionary, with the key being the string value of integer i ? What you need to do is allocate the dictionary outside your loop -
NSMutableDictionary *dict=[NSMutableDictionary new];
for (i=0; i<=57; i++) {
NSString *keysString = [csvArray objectAtIndex:i];
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
NSLog(#"Serial No %d %#",i,keysArray);
NSString *string = [NSString stringWithFormat:#"%d", i];
dict[string]=keysArray;
}
I am not sure why you would want to do this, because this is basically an array. You could simply do -
NSMutableArray *outputArray=[NSMutableArray new];
for (NSString *keysString in csvArray) {
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
[outputArray addObject:keysArray];
}
i have an csv file having some duplicate member, i want to delete duplicate and store sort values in an array, i am using following procedure , but its don't give me unique array.
here is my csv value file content
37.46768876,-122.29178052
37.46797307,-122.29193961
37.46825147,-122.29210281
37.46852845,-122.29226818
37.46878976,-122.29244219
37.46905295,-122.29263363
37.46930994,-122.29282659
37.46956224,-122.2930368
37.46980661,-122.29324794
37.47004943,-122.29347317
37.47029083,-122.29370551
37.46768876,-122.29178052
37.46797307,-122.29193961
37.46825147,-122.29210281
37.46852845,-122.29226818
37.46878976,-122.29244219
37.46905295,-122.29263363
37.46930994,-122.29282659
37.46956224,-122.2930368
37.46980661,-122.29324794
37.47004943,-122.29347317
37.47029083,-122.29370551
37.47052113,-122.29393953
37.47074882,-122.29417431
37.47098645,-122.29441454
37.47121917,-122.29465652
37.47146019,-122.2948939
37.47169204,-122.29512775
37.47193243,-122.29536731
37.47216892,-122.29559597
37.4724045,-122.29584441
37.47263575,-122.29607826
37.47287359,-122.29631245
37.47310992,-122.29655586
37.47335094,-122.29678896
37.47358589,-122.2970276
37.47382733,-122.29725927
37.47407652,-122.29748533
37.47432651,-122.29770016
37.47457788,-122.29788741
37.47484795,-122.29807718
37.47511504,-122.29823928
37.46768876,-122.29178052
37.46797307,-122.29193961
37.46825147,-122.29210281
37.46852845,-122.29226818
37.46878976,-122.29244219
37.46905295,-122.29263363
37.46930994,-122.29282659
37.46956224,-122.2930368
37.46980661,-122.29324794
37.47004943,-122.29347317
37.47029083,-122.29370551
37.47052113,-122.29393953
37.47074882,-122.29417431
37.47098645,-122.29441454
37.47121917,-122.29465652
37.47146019,-122.2948939
37.47169204,-122.29512775
37.47193243,-122.29536731
37.47216892,-122.29559597
37.4724045,-122.29584441
37.47263575,-122.29607826
37.47287359,-122.29631245
37.47310992,-122.29655586
37.47335094,-122.29678896
37.47358589,-122.2970276
37.47382733,-122.29725927
37.47407652,-122.29748533
37.47432651,-122.29770016
37.47457788,-122.29788741
37.47484795,-122.29807718
37.47511504,-122.29823928
37.47539512,-122.29839703
37.47567109,-122.29853676
37.47596509,-122.29866961
37.47624844,-122.2987909
37.47654113,-122.29890078
37.47684146,-122.29899726
37.47714065,-122.29908334
37.47744621,-122.29914235
37.47775391,-122.29919189
37.47805503,-122.29923078
37.46768876,-122.29178052
37.46797307,-122.29193961
37.46825147,-122.29210281
37.46852845,-122.29226818
37.46878976,-122.29244219
37.46905295,-122.29263363
37.46930994,-122.29282659
37.46956224,-122.2930368
37.46980661,-122.29324794
37.47004943,-122.29347317
37.47029083,-122.29370551
37.47052113,-122.29393953
37.47074882,-122.29417431
37.47098645,-122.29441454
37.47121917,-122.29465652
37.47146019,-122.2948939
37.47169204,-122.29512775
37.47193243,-122.29536731
37.47216892,-122.29559597
37.4724045,-122.29584441
37.47263575,-122.29607826
37.47287359,-122.29631245
37.47310992,-122.29655586
37.47335094,-122.29678896
37.47358589,-122.2970276
37.47382733,-122.29725927
37.47407652,-122.29748533
37.47432651,-122.29770016
37.47457788,-122.29788741
37.47484795,-122.29807718
37.47511504,-122.29823928
37.47539512,-122.29839703
37.47567109,-122.29853676
37.47596509,-122.29866961
37.47624844,-122.2987909
37.47654113,-122.29890078
37.47684146,-122.29899726
37.47714065,-122.29908334
37.47744621,-122.29914235
37.47775391,-122.29919189
37.47805503,-122.29923078
37.47836852,-122.29925626
37.47867584,-122.29926607
37.47898412,-122.29925944
37.47928265,-122.29924209
37.47959504,-122.29920555
37.47990379,-122.2991675
37.4802021,-122.29911704
37.48050104,-122.29907018
37.48081016,-122.29901151
37.48112252,-122.29896314
37.48143034,-122.2989116
37.48173368,-122.29885946
37.48204679,-122.298808
37.48235759,-122.2987603
37.48267635,-122.29871948
37.48296448,-122.29865444
37.48327373,-122.29860566
37.48356664,-122.29855578
37.48386847,-122.29850608
My code...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,
YES);
NSString *docDirectory = [paths objectAtIndex:0];
NSString *outputFileName = [docDirectory stringByAppendingPathComponent:#"People.csv"];
NSString* fileContents = [NSString stringWithContentsOfFile:outputFileName encoding:nil error:nil];
NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"point string=%#",pointStrings);
NSMutableArray* points = [[NSMutableArray alloc] initWithCapacity:pointStrings.count];
for(int idx = 0; idx < pointStrings.count-1; idx++)
{
// break the string down even further to latitude and longitude fields.
NSString* currentPointString = [pointStrings objectAtIndex:idx];
NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue];
CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];
CLLocation* currentLocation = [[[CLLocation alloc] initWithLatitude:latitude longitude:longitude] autorelease];
[points addObject:currentLocation];
}
NSMutableArray *pointsunique = [NSMutableArray array];
for (id obj in points) {
if (![pointsunique containsObject:obj]) {
[pointsunique addObject:obj];
}
}
//sortlocationArray = [NSOrderedSet orderedSetWithArray:locationArray];
NSLog(#"pointsunique count %d",[pointsunique count]);//same count,expect less then points count
NSLog(#"temp1 count %d",[points count]);//same count
NSLog(#"pointsunique %#",pointsunique);
As the question says I am trying to add pins to my map based on the coordinates returned by my php file. Said file returns the following results
[{"dogid":"1","latitude":"15.435786","longitude":"-21.318447"},{"dogid":"1","latitude":"14.00000","longitude":"-18.536711"}]
What I am doing (well I believe i am) is taking the values from the link and saving them to a string. Secondly, save that string value to an array. Then, I go thru this array and save out the latitude and longitude and assign it to CLLocationCordinate 2dcoord. After whch I expect both pins to be dropped on whatever location they received.
However, what occurs is: Upon running the program, when it arrives on this lin
for (NSDictionary *row in locations) {
the loop is not run to assign the values, and it jumps to the end. Oddly, a single pin is dropped on the map (thou location doesnt appear to be the values that it waas passed).
Would appreciate a little incite into the matter.
Thanks
- (void)viewDidAppear:(BOOL)animated
{
NSMutableArray *annotations = [[NSMutableArray alloc] init];
NSURL *myURL =[NSURL URLWithString:#"link.php"];
NSError *error=nil;
NSString *str=[NSString stringWithContentsOfURL:myURL encoding:NSUTF8StringEncoding error:&error];
CLLocationCoordinate2D coord;
NSArray *locations=[NSArray arrayWithContentsOfFile:str];
for (NSDictionary *row in locations) {
NSNumber *latitude = [row objectForKey:#"latitude"];
NSNumber *longitude = [row objectForKey:#"longitude"];
// NSString *title = [row objectForKey:#"title"];
//Create coordinates from the latitude and longitude values
coord.latitude = latitude.doubleValue;
coord.longitude = longitude.doubleValue;
}
MKPointAnnotation *pin = [[MKPointAnnotation alloc] init];
pin.coordinate = coord;
[self.mapView addAnnotation:pin];
}
It looks like you are trying to save api response to and Array.
Api always returns json string which is NSString.
You need to convert decode json string.
In your case
NSString *str=[NSString stringWithContentsOfURL:myURL encoding:NSUTF8StringEncoding error:&error];
you need to decode str with [NSJSONSerialization JSONObjectWithData:<#(NSData )#> options:<#(NSJSONReadingOptions)#> error:<#(NSError *)#>] which give you proper array of dictionary.
Hope it will help you
This is my code
for(id tempLangItem in jp.staffData)
{
NSMutableDictionary *temp=[[NSMutableDictionary alloc] initWithDictionary:tempLangItem];
NSString *name = [temp objectForKey:#"lang_name"];
NSLog(#"item_name =%#",name);
NSLog(#"value in dictionary=%#",temp);
}
These are log details
item_name =marinieres
value_in_dictionary={
"lang_id" = 2;
"lang_name" = "\U7a46\U840a\U65afmarinieres";
time = "2013-06-05 05:14:50";
}
why it is giving lang_name=\U7a46\U840a\U65afmarinieres in value_in_dictionary logs while it is displaying correct in item_name log.
Tried
NSMutableDictionary *temp=[[NSMutableDictionary alloc]init];
[temp setObject:#"marinieres" forKey:#"lang_name"];
NSString *name = [temp objectForKey:#"lang_name"];
NSLog(#"item_name =%#",name);
NSLog(#"value in dictionary=%#",temp);
and what my log shows
2013-06-06 12:38:02.337 Cool[96423:11303] item_name =marinieres
2013-06-06 12:38:04.022 Cool[96423:11303] value in dictionary={
"lang_name" = marinieres;
}
1 Quick question: if it is an NSDictionary why you creating a new instance?
NSMutableDictionary *temp=[[NSMutableDictionary alloc] initWithDictionary:tempLangItem];
try with tempLangItem