NSMutableArray 解析 csv 不工作?
NSMutableArray parsing csv not working?
我有这段代码,我在其中使用 NSMutableArray 来解析 csv 文件。没有错误阻止我使用 运行 该应用程序,但是地图不显示任何内容。
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;
}
我想我调用对象或 MKMapPoint 的方式肯定有问题,但我没能找到阻止应用程序显示数据的原因。我试过同时使用 "initWithObjects" 和删除 "if ([infos count] > 1){" 但是当 运行 它崩溃显示 "NSMutableArray *latitude = [[NSMutableArray alloc]init];".
中的故障点
根据您之前关于此项目的问题,您希望在更高层次上执行以下操作:
- 解析每行都有坐标数据的 CSV 文件。忽略具有 "null" 数据的行。 (为了这个答案的目的,让我们忽略可以使用预构建的 CSV 解析器,或者完全使用不同的格式。)
- 显示包含 "good" 数据的行的注释。
- 用一条线连接所有注释。
对于要求 1 (R1),您已经知道如何加载 CSV 文件、循环遍历行以及用 "null" 数据识别行。
对于要求 2 (R2),经过一些研究,您知道您可以一次创建一个注释并将其添加到地图,而地图 不需要提前知道如何许多你会添加,这意味着前两个要求可以在同一个循环中完成。
对于要求 3 (R3),经过一些研究,您知道要创建折线并将其添加到地图,您需要提前知道 直线上有多少个点。
对于 R1 和 R2,您将遍历 CSV 的行并识别非空行。
这意味着您将知道在处理 R1 和 R2 的循环之后折线 中有多少点。这意味着必须在该循环之后创建折线。
但是要创建折线,您不仅需要点数,还需要每个点的坐标。
这意味着在遍历 CSV 中的行时,您需要将坐标数据保存在某处(按照它在 CSV 中出现的顺序)。
在 Objective-C 中,一种方便的结构是 NSMutableArray
。
允许您在事先不知道将添加多少对象的情况下向其中添加数据。
所以现在我们有了这个非常高级的计划:
- 遍历 CSV 文件,忽略包含空数据的行,创建并添加注释,将行数据添加到
NSMutableArray
(NSMA)。
- 使用NSMA中的点数据创建折线,将折线添加到地图中。
有了这个计划,我们发现我们需要 一个 NSMutableArray
。请注意,在现有代码中,您有一个 Location
class 保存(或可能保存)CSV 每一行的所有数据。
这意味着我们可以简单地将这些 Location
个对象添加到 NSMA。 NSMutableArray
s 可以容纳任何类型的对象(它们不必只是 NSString
s)。
所以这里有一个更详细的计划:
- 初始化一个名为
filteredLocations
的 NSMutableArray
(例如 NSMutableArray *filteredLocations = [NSMutableArray array];
)。
- 遍历 CSV 文件,忽略包含空数据的行,创建一个
Location
对象并添加为注释,将 Location
对象添加到 filteredLocations
(例如 [filteredLocations addObject:annotation];
).
- 初始化 (malloc) 一个 C 数组来保存折线的点,点数为
filteredLocations
。
- 遍历
filteredLocations
,将 filteredLocations
中的点添加到 C 数组。
- 创建折线并将其添加到地图。
在此计划说明中,我们有 两个独立的循环:第一个用于 R1 和 R2。第二个是给R3的。
如果需要,我将 post 实现此计划的示例代码。
首先,只是为了解释你最近的 NSRangeException
错误,它发生在这一行:
if([[latitude objectAtIndex:4] isEqualToString:@"NULL"] || ...
因为您已将 latitude
声明为数组,并且 if
第一次在循环中执行,latitude
只有一个对象(此 [= 以上几行) 31=] 你做 [latitude addObject:...
)。数组的索引从零开始,因此具有一个对象的数组的边界是零到零,因此错误消息显示 index 4 beyond bounds [0 .. 0]
.
其余代码还有许多其他问题。
本回答篇幅不够,无法详细说明。
我劝你,如果可能的话,停下来,退后一步,然后重新开始一个更简单的项目或教程,最重要的是,学习一般编程的绝对基础知识.
下面是一个代码示例,应该可以根据您的示例数据运行:
-(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];
}
我有这段代码,我在其中使用 NSMutableArray 来解析 csv 文件。没有错误阻止我使用 运行 该应用程序,但是地图不显示任何内容。
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;
}
我想我调用对象或 MKMapPoint 的方式肯定有问题,但我没能找到阻止应用程序显示数据的原因。我试过同时使用 "initWithObjects" 和删除 "if ([infos count] > 1){" 但是当 运行 它崩溃显示 "NSMutableArray *latitude = [[NSMutableArray alloc]init];".
中的故障点根据您之前关于此项目的问题,您希望在更高层次上执行以下操作:
- 解析每行都有坐标数据的 CSV 文件。忽略具有 "null" 数据的行。 (为了这个答案的目的,让我们忽略可以使用预构建的 CSV 解析器,或者完全使用不同的格式。)
- 显示包含 "good" 数据的行的注释。
- 用一条线连接所有注释。
对于要求 1 (R1),您已经知道如何加载 CSV 文件、循环遍历行以及用 "null" 数据识别行。
对于要求 2 (R2),经过一些研究,您知道您可以一次创建一个注释并将其添加到地图,而地图 不需要提前知道如何许多你会添加,这意味着前两个要求可以在同一个循环中完成。
对于要求 3 (R3),经过一些研究,您知道要创建折线并将其添加到地图,您需要提前知道 直线上有多少个点。
对于 R1 和 R2,您将遍历 CSV 的行并识别非空行。
这意味着您将知道在处理 R1 和 R2 的循环之后折线 中有多少点。这意味着必须在该循环之后创建折线。
但是要创建折线,您不仅需要点数,还需要每个点的坐标。
这意味着在遍历 CSV 中的行时,您需要将坐标数据保存在某处(按照它在 CSV 中出现的顺序)。
在 Objective-C 中,一种方便的结构是 NSMutableArray
。
所以现在我们有了这个非常高级的计划:
- 遍历 CSV 文件,忽略包含空数据的行,创建并添加注释,将行数据添加到
NSMutableArray
(NSMA)。 - 使用NSMA中的点数据创建折线,将折线添加到地图中。
有了这个计划,我们发现我们需要 一个 NSMutableArray
。请注意,在现有代码中,您有一个 Location
class 保存(或可能保存)CSV 每一行的所有数据。
这意味着我们可以简单地将这些 Location
个对象添加到 NSMA。 NSMutableArray
s 可以容纳任何类型的对象(它们不必只是 NSString
s)。
所以这里有一个更详细的计划:
- 初始化一个名为
filteredLocations
的NSMutableArray
(例如NSMutableArray *filteredLocations = [NSMutableArray array];
)。 - 遍历 CSV 文件,忽略包含空数据的行,创建一个
Location
对象并添加为注释,将Location
对象添加到filteredLocations
(例如[filteredLocations addObject:annotation];
). - 初始化 (malloc) 一个 C 数组来保存折线的点,点数为
filteredLocations
。 - 遍历
filteredLocations
,将filteredLocations
中的点添加到 C 数组。 - 创建折线并将其添加到地图。
在此计划说明中,我们有 两个独立的循环:第一个用于 R1 和 R2。第二个是给R3的。
如果需要,我将 post 实现此计划的示例代码。
首先,只是为了解释你最近的
NSRangeException
错误,它发生在这一行:
if([[latitude objectAtIndex:4] isEqualToString:@"NULL"] || ...
因为您已将 latitude
声明为数组,并且 if
第一次在循环中执行,latitude
只有一个对象(此 [= 以上几行) 31=] 你做 [latitude addObject:...
)。数组的索引从零开始,因此具有一个对象的数组的边界是零到零,因此错误消息显示 index 4 beyond bounds [0 .. 0]
.
其余代码还有许多其他问题。
本回答篇幅不够,无法详细说明。
我劝你,如果可能的话,停下来,退后一步,然后重新开始一个更简单的项目或教程,最重要的是,学习一般编程的绝对基础知识.
下面是一个代码示例,应该可以根据您的示例数据运行:
-(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];
}