【问题标题】:iOS Terminating app due to uncaught exceptions when parsing JSON object由于解析 JSON 对象时未捕获的异常,iOS 终止应用程序
【发布时间】:2015-02-02 06:01:53
【问题描述】:

这是我一周前开始学习为 iOS 开发以来的一个新错误,我完全不知道是什么原因导致它以及为什么应用程序突然崩溃。如果您可以查看我的代码并建议如何修复此运行时错误,那么我的代码一定有问题。

*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)'
*** First throw call stack:
(0x2514c49f 0x32902c8b 0x2514c3e5 0x25079a6d 0xd01cb 0x2863f9fb 0x2863f9a1 0x2862a613 0x28747781 0x287fdc6b 0x286041ad 0x286390c1 0x2863899d 0x2860f15d 0x28882ab9 0x2860dbb9 0x25112d57 0x25112167 0x251107cd 0x2505e3c1 0x2505e1d3 0x2c45c0a9 0x2866dfa1 0xa3911 0x32e82aaf)
libc++abi.dylib: terminating with uncaught exception of type NSException

这是我的代码 sn-p

- (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];
    }
}

【问题讨论】:

  • Objective-C 中的异常仅用于不可恢复的错误,而不是控制流。您需要编写不会导致异常的代码。
  • 为了强调 Zaph 的观点,Objective-C 的 try-catch 块不会捕捉到您在开发期间通过适当的测试和调试无法阻止的东西。
  • 原因是“Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)”

标签: ios objective-c json


【解决方案1】:

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

jsonData = [tArray objectAtIndex:1];

【讨论】:

    【解决方案2】:

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

    jsonData = [tArray objectAtIndex:1];
    

    这正是您在问题中提出的异常的粗体部分所说的内容。

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

    相反,有以下解决方案:

    1. 任何时候我们需要访问数组中的第一个对象,我们都可以安全地使用firstObject 方法,它总是返回索引为 0 的对象,除非数组为空,在这种情况下它会返回nil。如果在数组为空时访问数组的第 0 个索引,仍然会出现索引越界异常。
    [myArray firstObject];
    
    1. 任何时候我们需要访问数组中的最后一个对象,都可以使用lastObject 方法安全地完成。这与firstObject 相同,只是它查看数组的最后一个索引。无论数组中有多少对象,这都会返回最后一个。如果它是一个空数组,它会安全地返回nil
    [myArray lastObject];
    
    1. 最后,最适合您的情况的场景是,当我们需要遍历数组中的所有元素时,我们应该使用某种形式的快速枚举来实现。在大多数情况下最容易使用和最常用的方法就是使用forin 循环。使用forin 循环有几个优点。首先,they're faster than a regular 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。当 Apple 发布 Swift 和 iOS 8 时,他们也经历了 Objective-C 并消除了几乎所有 id 的使用,取而代之的是 instancetype。他们不再使用id。但这一个仍然存在。为什么?因为它必须。在这种情况下,我们使用id,因为我们不能使用instancetype。我们使用id,因为返回值可能是NSArray,也可能是NSDictionary。 (它也可能是 NSNumberNSString 对象。)

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

    【讨论】:

      【解决方案3】:

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

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

      像这样!!!那就永远不会崩溃了……

      一切顺利...

      【讨论】:

      • 我尝试了您所有的解决方案建议,但仍然无法相应地工作
      • 这也不起作用; if (tArray.count==0 && selectedSegment == 0) { //切换正确的视图可见 NSLog(@"Clicked Make"); jsonData = [tArray objectAtIndex:0]; self.displayInsurer.text=jsonData[@"insurerName"]; } else if (tArray.count==1 && selectedSegment == 1) { //切换正确的视图可见 NSLog(@"Clicked RegNo"); jsonData = [tArray objectAtIndex:1]; self.displayInsurer.text=jsonData[@"insurerName"]; }
      【解决方案4】:

      您有一个数组,其中有 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"];  
      }
      

      【讨论】:

      • 如何从我的数组中提取 2 个元素,因为我肯定是 Objective-c 的新手
      • 你需要一个包含两个元素的数组!阅读所有答案,他们都说同样的话。
      • 我现在知道是什么导致了错误,谢谢大家。您的回答很有帮助
      猜你喜欢
      • 2015-12-19
      • 1970-01-01
      • 2017-01-08
      • 2015-08-20
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多