简体   繁体   中英

NSRangeException Error

I am trying to populate a table view after parsing objects from JSON. I want to set the number of rows to the count of the parsed objects.

Here's my viewDidLoad code:

    - (void)viewDidLoad
{
[super viewDidLoad];

// initializing data source
[self setNotifications:[[NSMutableArray alloc] init]];

NSURL *url = [NSURL URLWithString:SourceURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];


AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

    [self setNotifications:[JSON objectForKey:@"notifications"]];
    //  [[self tableView] setHidden:NO];
    [[self tableView] reloadData];



} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
    NSLog(@"Request Failure Because %@",[error userInfo]);
}];

[operation start];

}

Here is one of my datasource methods (I believe the error must be here):

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if ([self notifications] && [[self notifications] count] ) {
        return [[self notifications] count];
    } else{
        return 0;
    }
}

And here is my full error message:

> *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 ..
> 0]'
> *** First throw call stack: (0x13c4012 0x118ce7e 0x1379b44 0x510c04 0x300ea0 0x2b5c4e 0x2b8224 0x17c952 0x17c2dc 0xc4a9d14 0x26e0 0x16ea2
> 0x18409 0x162753f 0x1639014 0x16297d5 0x136aaf5 0x1369f44 0x1369e1b
> 0x22647e3 0x2264668 0xd0ffc 0x1f1d 0x1e45) libc++abi.dylib: terminate
> called throwing an exception

UPDATE :

Here is my cellForRowAtIndexpath method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"readNotification";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (!cell){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
    }

    NSDictionary *notification = [[self notifications] objectAtIndex:[indexPath row]];
    [[cell textLabel] setText:[notification objectForKey:@"from"]];
    [[cell detailTextLabel] setText:[notification objectForKey:@"date"]];
    return cell;
}

UPDATE 2

I added some logs to the project, and it provided some interesting output:

2013-08-06 23:53:03.994 NotificationReader[1193:c07] 1. before request 2013-08-06 23:53:04.023 NotificationReader[1193:c07] 2. json parshing operation started 2013-08-06 23:53:04.031 NotificationReader[1193:c07] 3. entered the numberOfRowsInSection block 2013-08-06 23:53:04.040 NotificationReader[1193:c07] No notifications 2013-08-06 23:53:04.319 NotificationReader[1193:c07] 3. entered the numberOfRowsInSection block 2013-08-06 23:53:04.320 NotificationReader[1193:c07] There were 14 notifications 2013-08-06 23:53:08.260 NotificationReader[1193:c07] * Terminating app due to uncaught exception

So first it thinks that my array is empty, then it reloads and gets the count of notifications right. Unfortunately, it never enters the cellForRowAtIndexPath method..

UPDATE 3

I have added an exception breakpoint to my project, plus did some additional logging, and I'm assuming, it somehow has trouble reloading the table view. Here is the outcome so far:

2013-08-07 08:40:58.104 NotificationReader[433:c07] 1. before request
2013-08-07 08:40:58.107 NotificationReader[433:c07] 2. json parshing operation started
2013-08-07 08:40:58.113 NotificationReader[433:c07] 3. entered the numberOfRowsInSection block
2013-08-07 08:40:58.120 NotificationReader[433:c07] Found 0 notifications!
2013-08-07 08:41:10.852 NotificationReader[433:c07] Trying to reload data
2013-08-07 08:41:10.853 NotificationReader[433:c07] data needs to be reloaded
2013-08-07 08:41:10.854 NotificationReader[433:c07] 3. entered the numberOfRowsInSection block
2013-08-07 08:41:10.855 NotificationReader[433:c07] Found 14 notifications!
2013-08-07 08:41:10.858 NotificationReader[433:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack:
(0x13c5012 0x118de7e 0x137ab44 0x511c04 0x301ea0 0x2b6c4e 0x2b9224 0x17d952 0x17d2dc 0xc4c0d14 0x351b 0x162853f 0x163a014 0x162a7d5 0x136baf5 0x136af44 0x136ae1b 0x22657e3 0x2265668 0xd1ffc 0x2c4d 0x2b75)
libc++abi.dylib: terminate called throwing an exception}

Stack trace:

#0  0x0118de52 in objc_exception_throw ()
#1  0x0137ab44 in -[__NSArrayI objectAtIndex:] ()
#2  0x00511c04 in -[UITableViewDataSource tableView:heightForRowAtIndexPath:] ()
#3  0x00301ea0 in -[UITableViewController tableView:heightForRowAtIndexPath:] ()
#4  0x002b6c4e in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] ()
#5  0x002b9224 in -[UITableViewRowData numberOfRows] ()
#6  0x0017d952 in -[UITableView noteNumberOfRowsChanged] ()
#7  0x0017d2dc in -[UITableView reloadData] ()
#8  0x0c4a9d14 in -[UITableViewAccessibility(Accessibility) reloadData] ()
#9  0x0000351b in __36-[NRTableViewController viewDidLoad]_block_invoke_2 at /Users/jozsef/Development/NotificationReader/NotificationReader/NRTableViewController.m:52

I tried using lldb with this result:

(lldb) po [[self notifications] count]
error: Execution was interrupted, reason: Attempted to dereference an invalid pointer..
The process has been returned to the state before execution.

This is caused by trying to access an index beyond the bounds of an array. By the look of things, the only array access is in -tableView:cellForRowAtIndexPath: :

NSDictionary *notification = [[self notifications] objectAtIndex:[indexPath row]];

I expect this is where the exception is raised.

You can find out for certain by adding a "Add Exceptions Breakpoint..." from the breakpoints navigator.

Fix this by confirming that [indexPath row] is within the bounds of the [self notifications] array. Or if you expect this should always be within the bounds, then figure out why it could be out of bounds.

On a side note, you could rewrite one of your methods as follows:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.notifications count];
}

If self.notifications is nil, this will return 0. If count is 0, then it will obviously return 0. So that's all that is required.

EDIT: Finally, you could also rewrite the array access using subscripting, as follows:

NSDictionary *notification = self.notifications[indexPath.row];

Make sure you call the UI updates on the main thread in the success block of AFJSONRequestOperation, ie

AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

    // update on the main thread!
    dispatch_async(dispatch_get_main_queue(), ^{
        [self setNotifications:[JSON objectForKey:@"notifications"]];
        //  [[self tableView] setHidden:NO];
        [[self tableView] reloadData];
    });        

} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
    NSLog(@"Request Failure Because %@",[error userInfo]);
}];

The commenters are correct, you should debug this sort of thing by setting breakpoints and stepping through the code. Supplement this approach with log statements.

You should also set an "All Exceptions Breakpoint" in Xcode (command-6 and then hit the + button at the bottom left).

The error is likely NOT happening in numberOfRowsInSection . Is it probably occurring in cellForRowAtIndexPath where you do:

NSDictionary *notification = [[self notifications] objectAtIndex:[indexPath row]];

Just as you do nil and count checking in numberOfRowsInSection you should do the same here:

if (self.notifications) {
    if (indexPath.row < [self.notifications count]) {
        NSDictionary *notification = [[self notifications] objectAtIndex:[indexPath row]];`
        //...
    }
}

My guess is that the JSON response isn't what you're expecting it to be and therefore self.notifications isn't what you'd expect it to be.

After running the code on different machines, it all seemed to work as it should. There must have been some junk in my configuration, so I added the project again and can confirm that it's working. Thank you for everyone who responded! @Sam, special thanks to you for your testing and patience!

Oh Sam's answer is excellent, but even doing everything he mentioned didn't work out for me until I realize that my Table view had Content set to Static Cells instead of Dynamic Prototypes in my storyboard ! 动态的原型表视

Even if you define your own numberOfRowsInSection like this:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section
{
    return [self.notifications count];
}

If it's not dynamic, chances it will fail ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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