Reputation: 411
This is a new error since I started learning to develop for iOS a week ago and I totally don't have a clue what is causing it and why the app suddenly crushes. There must be something wrong in my code if you may have a look at it and kindly suggest how to fix this run-time bug.
*** 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
Here is my code snippet
- (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];
}
}
Upvotes: 0
Views: 644
Reputation: 62052
So, as KerrM's answer points out, this exception is happening because we're trying to access an index which doesn't exist in our array.
jsonData = [tArray objectAtIndex:1];
This is exactly what the bolded part of the exception you put in the question is saying.
So what should we do to fix it? Well, I don't find the other answers that offer solutions to be particularly that great. In all of them, we're still accessing a hard-coded array index. Sure, we're putting a check in to make sure it exists, but very, very rare should it be that you actually need to directly access an array index that you can hardcode.
Instead, there are these solutions:
firstObject
method, which will always return the object at index 0, unless the array is empty, in which case it will return nil
. If you access an array's 0th index when it is empty, you still get the index out of bounds exception.[myArray firstObject];
lastObject
method. This is the same as firstObject
, except it looks at the last index of the array. No matter how many objects in the array, this will return the last one. And if it's an empty array, it will safely return nil
.[myArray lastObject];
forin
loop. There are several advantages to using a forin
loop. For a start, they're faster than a regular for
loop. But there are other advantages too. We're not accessing our array by index (which helps make the loop faster) and that means we can't have an index out of bounds exception. Finally though, it just looks a whole lot cleaner and more readable than a regular for
loop.for (NSDictionary *jsonData in tArray) {
[mySegments addObject:jsonData[@"vehicleMake"]];
[mySegments addObject:jsonData[@"vehicleRegNo"]];
}
In terms of answering the question of how come tArray
only has one object in it, you'll have to look at the JSON data itself. In fact, you should have already done this. There's no guarantee that the JSON data is an array of dictionaries. Most JSON or XML data I see typically has a dictionary as the root object. But the point is that the method signature looks like this:
+ (id)JSONObjectWithData:(NSData *)data
options:(NSJSONReadingOptions)opt
error:(NSError **)error
The return type is id
. When Apple released Swift and iOS 8, they also went through Objective-C and eliminated nearly all uses of id
, replacing most with instancetype
. They're moving away from the use of id
. But this one remains. Why? Because it must. In this case, we're using id
because we can't use instancetype
. We're using id
because the return value could be an NSArray
, or it could be an NSDictionary
. (It can probably also be an NSNumber
or NSString
object, perhaps.)
So we should definitely be clear on what the expected JSON looks like before we write the code to grab data out of it...
Upvotes: 1
Reputation: 1270
You have an array and you have 1 element in it. Now you are trying to extract 2nd element from it, [0] is first, and [1] is second.
Error-->> jsonData = [tArray objectAtIndex:i];
Check First wether it contains items are more than one
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"];
}
Upvotes: 0
Reputation: 222
You must first check the number of items in NSArray
before accessing them:
if (tArray.count > count) {
jsonData = [tArray objectAtIndex:count-1];
self.displayInsurer.text=jsonData[@"insurerName"];
}
like this!!! It will never crash then...
All the best...
Upvotes: 0
Reputation: 5240
Your array only has 1 item (at index 0) and you're trying to access an item at index 1 here:
jsonData = [tArray objectAtIndex:1];
Upvotes: 3