Jon Erickson
Jon Erickson

Reputation: 1976

iOS NSArray objectAtIndex beyond bounds

I have a UITableView that is populated from an array of data that is parsed from an XML feed. Im struggling to find the cause of this error and was wondering if anyone can help me. The error does not occur very often. It only occurs when the array count is large, for example 10-15 objects and then once refreshed, they array is then a lower number, like 3 - 4 objects. Normally the error is thrown on this line: FCCall *currentCall = [[dataController callsArray] objectAtIndex:((indexPath.row - 1 ) / 2)]; I added an exception breakpoint to break On Throw for All Exception and below is what it returned. I understand what the error is saying but cannot find the origin and it is very difficult to re-produce.

CoreFoundation`-[__NSArrayM objectAtIndex:]:
0x329cce54:  push   {r4, r5, r7, lr}
0x329cce56:  add    r7, sp, #8
0x329cce58:  sub    sp, #8
0x329cce5a:  movw   r1, #62216
0x329cce5e:  mov    r4, r2
0x329cce60:  movt   r1, #2113
0x329cce64:  add    r1, pc
0x329cce66:  ldr    r1, [r1]
0x329cce68:  ldr    r1, [r0, r1]
0x329cce6a:  cmp    r1, r4
0x329cce6c:  bhi    0x329ccef8                ; -[__NSArrayM objectAtIndex:] + 164
0x329cce6e:  movw   r0, #49640
0x329cce72:  cmp    r1, #0
0x329cce74:  movt   r0, #2111
0x329cce78:  add    r0, pc
0x329cce7a:  ldr    r0, [r0]
0x329cce7c:  ldr    r0, [r0]
0x329cce7e:  beq    0x329cce9c                ; -[__NSArrayM objectAtIndex:] + 72
0x329cce80:  movw   r2, #17054
0x329cce84:  subs   r5, r1, #1
0x329cce86:  movt   r2, #2113
0x329cce8a:  movw   r3, #61062
0x329cce8e:  movt   r3, #16
0x329cce92:  add    r2, pc
0x329cce94:  add    r3, pc
0x329cce96:  strd   r4, r5, [sp]
0x329cce9a:  b      0x329cceb2                ; -[__NSArrayM objectAtIndex:] + 94
0x329cce9c:  movw   r2, #17044
0x329ccea0:  movt   r2, #2113
0x329ccea4:  movw   r3, #61034
0x329ccea8:  movt   r3, #16
0x329cceac:  add    r2, pc
0x329cceae:  str    r4, [sp]
0x329cceb0:  add    r3, pc
0x329cceb2:  movs   r1, #0
0x329cceb4:  bl     0x329dce60                ; CFStringCreateWithFormat
0x329cceb8:  bl     0x329c897c                ; CFMakeCollectable
0x329ccebc:  mov    r1, r0
0x329ccebe:  movs   r0, #0
0x329ccec0:  bl     0x329ffa8c                ; _CFAutoreleasePoolAddObject
0x329ccec4:  movw   r2, #50122
0x329ccec8:  mov    r3, r0
0x329cceca:  movt   r2, #2111
0x329ccece:  movw   r1, #25010
0x329cced2:  add    r2, pc
0x329cced4:  movt   r1, #2112
0x329cced8:  movw   r0, #26280
0x329ccedc:  ldr    r2, [r2]
0x329ccede:  add    r1, pc
0x329ccee0:  movt   r0, #2112
0x329ccee4:  ldr    r1, [r1]
0x329ccee6:  movs   r4, #0
0x329ccee8:  add    r0, pc
0x329cceea:  str    r4, [sp]
0x329cceec:  ldr    r0, [r0]
0x329cceee:  ldr    r2, [r2]
0x329ccef0:  blx    0x32abfeec                ; symbol stub for: -[NSMutableOrderedSet removeObjectsInRange:inOrderedSet:]
0x329ccef4:  blx    0x32abfe8c                ; symbol stub for: -[NSMutableOrderedSet removeObjectsAtIndexes:]
0x329ccef8:  movw   r1, #62064
0x329ccefc:  movt   r1, #2113
0x329ccf00:  movw   r3, #62048
0x329ccf04:  add    r1, pc
0x329ccf06:  movt   r3, #2113
0x329ccf0a:  movw   r2, #62048
0x329ccf0e:  ldr    r1, [r1]
0x329ccf10:  add    r3, pc
0x329ccf12:  movt   r2, #2113
0x329ccf16:  ldr    r3, [r3]
0x329ccf18:  add    r2, pc
0x329ccf1a:  ldr    r2, [r2]
0x329ccf1c:  ldr    r1, [r0, r1]
0x329ccf1e:  ldr    r3, [r0, r3]
0x329ccf20:  ldr    r0, [r0, r2]
0x329ccf22:  add.w  r2, r4, r1, lsr #2
0x329ccf26:  sub.w  r1, r2, r3, lsr #2
0x329ccf2a:  lsrs   r3, r3, #2
0x329ccf2c:  cmp    r3, r2
0x329ccf2e:  it     hi
0x329ccf30:  movhi  r1, r2
0x329ccf32:  ldr.w  r0, [r0, r1, lsl #2]
0x329ccf36:  add    sp, #8
0x329ccf38:  pop    {r4, r5, r7, pc}
0x329ccf3a:  nop    
0x329ccf3c:  nop    
0x329ccf3e:  nop 

Code:

- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // Returns the cell for the given indexPath 
    static NSString *cellidentifier1 = @"cell1";
    static NSString *cellidentifier2 = @"cell2";

    self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"dark-background.jpg"]];
    self.tableView.separatorColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"dark-background.jpg"]];

    // Invisible Cell
    if (indexPath.row % 2 == 0) {

        UITableViewCell * cell2 = [theTableView dequeueReusableCellWithIdentifier:cellidentifier2];

        if (cell2 == nil) {

            cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier2];
            [cell2.contentView setAlpha:0];
            [cell2 setUserInteractionEnabled:NO];
            [cell2 setBackgroundColor:[UIColor clearColor]];
        }
        return cell2;
    }

    // Standard Cell    
    SideSwipeTableViewCell *cell = (SideSwipeTableViewCell *)[theTableView dequeueReusableCellWithIdentifier:cellidentifier1];

    if (cell == nil) {

        cell = [[SideSwipeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier1];
    }

    if ([dataController numberOfCalls] >= 1) {

        FCCall *currentCall = [[dataController callsArray] objectAtIndex:((indexPath.row - 1 ) / 2)];

        cell.callLabel.text = currentCall.call;
        cell.locationLabel.text = currentCall.location;
        cell.wcccaNumberLabel.text = currentCall.wcccaNumber;
        cell.callNumberLabel.text = currentCall.callnumber;

        // Remove leading white space from units string
        NSString *units = [currentCall.units stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

        cell.unitsLabel.text = units;
        cell.stationLabel.text = currentCall.station;
    }
    return cell;
}

Method that refreshes the array:

- (void)refreshData:(id)object success:(void (^)(NSURLRequest *request, NSURL *url, NSArray *calls))success failure:(void (^)(NSURLRequest *request, NSURL *url, NSError *error))failure
{
    NSLog(@"Refresh Started");

    // Start the network activity indicator
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

    // Check to make sure we can even make an HTTP request
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.wccca.com/PITS"]];
    AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        NSLog(@"Reachable");

        // Get the URL we are going to use to parse with
        [FCDataController parserURL:[NSURL URLWithString:@"http://www.wccca.com/PITS"] completion:^(NSURL *url) {

            NSURLRequest *parserRequest = [NSURLRequest requestWithURL:url];
            AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:parserRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {

                // Remove all data from our previous calls aray
                [self performSelectorOnMainThread:@selector(removeCallsFromArray) withObject:nil waitUntilDone:YES];

                // Set the delegate for the XMLParser and start the parse operation
                XMLParser.delegate = self;
                BOOL successful = [XMLParser parse];

                // Determine if the parse operation was a success or not
                if (!successful) {

                    // Return the failure block because the parser failed
                    failure(request, url, [FCErrors parserError]);

                    // Stop the network activity indicator
                    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
                }
                else {

                    // Return the success block
                    success(request, url, calls);

                    // Stop the network activity indicator
                    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
                }

                NSLog(@"Refresh Finished");

            } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser) {

                NSLog(@"AFXMLOperation Error: %@", error.localizedDescription);

                // Remove all data from our previous calls aray
                [self performSelectorOnMainThread:@selector(removeCallsFromArray) withObject:nil waitUntilDone:YES];

                failure(parserRequest, url, [FCErrors badURLError]);

                // Stop the network activity indicator
                [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

                NSLog(@"Refresh Finished");
            }];
            [operation start];
        }];

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        NSLog(@"Unreachable. AFHTTPRequestOperation Error: %@", error.localizedDescription);

        // Remove all data from our previous calls aray
        [self performSelectorOnMainThread:@selector(removeCallsFromArray) withObject:nil waitUntilDone:YES];

        failure(request, nil, [FCErrors networkError]);

        // Stop the network activity indicator
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

        NSLog(@"Refresh Finished");
    }];
    [requestOperation start];
}

Upvotes: 1

Views: 1007

Answers (1)

vacawama
vacawama

Reputation: 154583

If your underlying data model has changed (such as refreshing your data that the table needs to display), you need to call reloadData on the tableView, otherwise it might request data for a row that no longer exists.

Upvotes: 1

Related Questions