繁体   English   中英

解析JSON对象时,由于未捕获的异常,导致iOS终止应用

[英]iOS Terminating app due to uncaught exceptions when parsing JSON object

自从一周前我开始学习为iOS开发以来,这是一个新错误,我完全不知道是什么原因以及导致应用突然崩溃的原因。 如果您可以看一下并在代码中出现问题,请提出如何修复此运行时错误的建议。

*由于未捕获的异常'NSRangeException'而终止应用程序,原因:'-[__ NSCFArray objectAtIndex:]:超出范围(1)的索引(1)'*第一个抛出调用堆栈:(0x2514c49f 0x32902c8b 0x2514c3e5 0x25079a6d 0xd01cb 0x2863f9fb 0x228612861286 0x2863899d 0x2860f15d 0x28882ab9 0x2860dbb9 0x25112d57 0x25112167 0x251107cd 0x2505e3c1 0x2505e1d3 0x2c45c0a9 0x2866dfa1 0xa3911 0x32e82aaf)异常为libc ++ abi.dylib的异常

这是我的代码片段

  - (IBAction)changeIns:(id)sender { UISegmentedControl *segmentedControl = (UISegmentedControl *) sender; NSInteger selectedSegment = segmentedControl.selectedSegmentIndex; if (selectedSegment == 0) { //toggle the correct view to be visible NSLog(@"Clicked"); jsonData = [tArray objectAtIndex:0]; self.displayInsurer.text=jsonData[@"insurerName"]; } else if (selectedSegment == 1) { //toggle the correct view to be visible jsonData = [tArray objectAtIndex:1]; self.displayInsurer.text=jsonData[@"insurerName"]; } else if (selectedSegment == 2) { //toggle the correct view to be visible } else if (selectedSegment == 3) { //toggle the correct view to be visible } else if (selectedSegment == 4) { //toggle the correct view to be visible } else if (selectedSegment == 5) { //toggle the correct view to be visible } else if (selectedSegment == 6) { //toggle the correct view to be visible } else if (selectedSegment == 7) { //toggle the correct view to be visible } else if (selectedSegment == 8) { //toggle the correct view to be visible } } -(void)setVariableFromNetwork { // NSInteger success = 0; @try { NSString *post =[[NSString alloc] initWithFormat:@"uid=%@&tag=getVehicleInfo",[[NSUserDefaults standardUserDefaults] stringForKey:@"userID"]]; NSLog(@"PostData: %@",post); NSURL *url=[NSURL URLWithString:@"URL"]; NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setURL:url]; [request setHTTPMethod:@"POST"]; [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:postData]; //[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]]; NSError *error = [[NSError alloc] init]; NSHTTPURLResponse *response = nil; NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; NSLog(@"Response code: %ld", (long)[response statusCode]); if ([response statusCode] >= 200 && [response statusCode] < 300) { NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding]; NSLog(@"Response ==> %@", responseData); NSError *error = nil; tArray = [NSJSONSerialization JSONObjectWithData:urlData options:kNilOptions error:&error]; NSLog(@"objects %@", [tArray description]); NSLog(@"first object %@", [tArray objectAtIndex:0]); NSDictionary *jsonData = [tArray objectAtIndex:0]; NSLog(@"dictionary %@", [jsonData description]); NSLog(@"vehicle %@", jsonData[@"vehicleMake"]); NSLog(@"Vehicle Number %@", jsonData[@"vehicleRegNo"]); int count = [tArray count]; NSMutableArray *mySegments = [[NSMutableArray alloc] initWithCapacity:count]; for (int i = 0; i<count; i++) { jsonData = [tArray objectAtIndex:i]; //NSString * desc = jsonData[@"vehicleMake"],"-", jsonData[@"vehicleMake"]; [mySegments addObject:jsonData[@"vehicleMake"]]; [mySegments addObject:jsonData[@"vehicleRegNo"]]; } [self.carSegment removeAllSegments]; self.carSegment = [self.carSegment initWithItems:mySegments]; } } @catch (NSException * e) { NSLog(@"Exception: %@", e); [self alertStatus:@"Sign in Failed." :@"Error!" :0]; } } 

您的数组只有1个项目(索引为0),并且您尝试在此处访问索引为1的项目:

jsonData = [tArray objectAtIndex:1];

因此,正如KerrM的答案所指出的,发生此异常是因为我们试图访问数组中不存在的索引。

jsonData = [tArray objectAtIndex:1];

这正是您在问题中加粗的粗体部分所说的。

那么我们应该怎么做才能解决它? 好吧,我找不到提供解决方案的其他答案那么出色。 在所有这些中,我们仍在访问硬编码的数组索引。 当然,我们要进行检查以确保它存在,但是,非常罕见的是,您实际上需要直接访问可以硬编码的数组索引。

相反,有以下解决方案:

  1. 每当我们需要访问数组中的第一个对象时,我们都可以使用firstObject方法安全地进行操作,该方法将始终返回索引为0的对象,除非数组为空,在这种情况下它将返回nil 如果在数组为空时访问数组的第0个索引,则仍然会超出索引范围。
[myArray firstObject];
  1. 每当我们需要访问数组中的最后一个对象时,都可以使用lastObject方法安全地进行lastObject 这与firstObject相同,除了它查看数组的最后一个索引。 无论数组中有多少个对象,这都将返回最后一个对象。 如果它是一个空数组,它将安全地返回nil
[myArray lastObject];
  1. 最后,最适合您的情况的场景是,当我们需要遍历数组中的所有元素时,我们应该使用某种形式的快速枚举。 在大多数情况下都可以使用的最简单,最通用的方法是使用forin循环。 使用forin循环有几个优点。 首先, 它们比常规的for loop更快 但是,还有其他优点。 我们不按索引访问数组(这有助于使循环更快),这意味着我们不能拥有超出范围的索引异常。 最后,尽管它看上去比常规的for循环更加整洁,可读性强。
for (NSDictionary *jsonData in tArray) {
    [mySegments addObject:jsonData[@"vehicleMake"]];
    [mySegments addObject:jsonData[@"vehicleRegNo"]];
}

在回答tArray只有一个对象的问题时,您必须查看JSON数据本身。 实际上,您应该已经做到了。 不能保证JSON数据是字典数组。 我看到的大多数JSON或XML数据通常都有一个字典作为根对象。 但关键是方法签名看起来像这样:

+ (id)JSONObjectWithData:(NSData *)data
                 options:(NSJSONReadingOptions)opt
                   error:(NSError **)error

返回类型为id 当苹果发布Swift和iOS 8时,他们还通过了Objective-C并消除了几乎所有id使用,大部分替换为instancetype 他们正在远离使用id 但这仍然存在。 为什么? 因为必须。 在这种情况下,我们使用id因为我们不能使用instancetype 我们使用id是因为返回值可以是NSArray ,也可以是NSDictionary (也许也可以是NSNumberNSString对象。)

因此,在编写代码以从中获取数据之前,我们绝对应该清楚预期的JSON是什么样的...

您有一个数组,并且其中有1个元素。 现在,您尝试从中提取第二个元素,[0]是第一个,[1]是第二个。

错误->> jsonData = [tArray objectAtIndex:i];

首先检查是否包含多个项目

if([tArray count]== 1 && selectedSegment == 0){
   jsonData = [tArray objectAtIndex:0];
else if ([tArray count]> 1 && selectedSegment == 1) {
    //toggle the correct view to be visible
    jsonData = [tArray objectAtIndex:1];
    self.displayInsurer.text=jsonData[@"insurerName"];  
}

您必须先检查NSArray的项目数,然后才能访问它们:

if (tArray.count > count) {
        jsonData = [tArray objectAtIndex:count-1];
        self.displayInsurer.text=jsonData[@"insurerName"];
}

像这样!!! 它将永远不会崩溃...

祝一切顺利...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM