TableView到达表格底部时出错

时间:2013-11-18 02:44:36

标签: ios iphone objective-c uitableview

当我滚动到TableView的底部时,我收到此错误,我不认为实际从服务器检索图片有任何错误。:

 *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (15) beyond bounds (15)'

这是我的.m文件,我将其剪切为文件中实际需要的部分:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row % 2 == 0)  {
        NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
        NSString *created = [tweet objectForKey:@"created_at"];
        NSLog(@"%@", created);
        static NSString *CellIdentifier = @"TweetCell";

        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }

        NSString *text = [tweet objectForKey:@"text"];
        NSString *name = [[tweet objectForKey:@"user"] objectForKey:@"name"];



        cell.textLabel.text = text;
        cell.detailTextLabel.text = [NSString stringWithFormat:@"by %@", name];

        return cell;
    }else {
        static NSString *CellIdentifier = @"InstagramCell";
        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];



        NSDictionary *entry = [self entries][indexPath.row];
        NSString *imageUrlString = entry[@"images"][@"low_resolution"][@"url"];
        NSURL *url = [NSURL URLWithString:imageUrlString];
        [cell.imageView setImageWithURL:url];
        return cell;
    }

}


- (void)fetchTweets {
    self.twitterClient = [[AFOAuth1Client alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.twitter.com/1.1/"] key:@"TWEETER_KEY" secret:@"TWEETER_SECRET"];

    [self.twitterClient authorizeUsingOAuthWithRequestTokenPath:@"/oauth/request_token" userAuthorizationPath:@"/oauth/authorize" callbackURL:[NSURL URLWithString:@"floadt://success"] accessTokenPath:@"/oauth/access_token" accessMethod:@"POST" scope:nil success:^(AFOAuth1Token *accessToken, id responseObject) {
        [self.twitterClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
        [self.twitterClient getPath:@"statuses/home_timeline.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
            NSArray *responseArray = (NSArray *)responseObject;
            [responseArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                NSLog(@"Success: %@", obj);
                tweets = responseArray;
                [self.tableView reloadData];
            }];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Error: %@", error);
        }];
    } failure:^(NSError *error) {
        NSLog(@"Error: %@", error);
    }];

}

3 个答案:

答案 0 :(得分:1)

numberOfRowsInSection的返回值与代码在cellForRowAtIndexPath中执行的数组访问之间需要紧密协调。

考虑到这一点,你的条目数组和推文数组都有4个元素。所以numberOfRowsInSection返回8.调用cellForRowAtIndexPath方法来配置第6行。您的代码将执行此操作:NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];

但等等......那个数组只有4个元素,对吧?在索引6处询问某些内容会产生您看到的崩溃。

编写将数组交错为单个数组的方法可能更简单,然后在numberOfRowsInSection中回答组合数组的计数。在cellForRowAtIndexPath中,数组元素本身应该能够告诉您具有哪种行(而不是索引)。取消引用组合数组并相应地配置表。

编辑 - 我会尝试在代码中更明确地提出我的建议:让我们说,为简单起见,“条目”和“推文”都是NSDictionaries的数组,并且您的应用程序希望首先在UI条目中组织它们,然后推文。

//在界面中:

@property (nonatomic, strong) NSArray *myModel;

//代码:

- (NSArray *)myModel {

    if (!_myModel) {
        NSMutableArray *array = [NSMutableArray arrayWithArray:[self entries]];
        [array addObjectsFromArray:tweets];
        _myModel = [NSArray arrayWithArray:array];
    }
    return _myModel;
}

我们称之为“myModel”是有原因的。它是表的数据源。数据源协议明确要求该数组(而不是其他数据)。

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

现在,cellForRowAtIndexPath将要求您配置多个(myModel计数)行,编号为0..count-1。您必须为所有数据源方法取消引用相同的数组 - myModel:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *myModelForThisRow = self.myModel[indexPath.row];
    // get the cell = deque...
    cell.textLabel.text = myModelForThisRow[@"someKey"];
    return cell;
}

如果您的推文或条目数组发生变化怎么办?没问题,只需重建这样的模型:

- (IBAction)tweetsOrEntriesDidChange:(id)sender {

    self.myModel = nil;          // the "lazy" getter will rebuild it
    [self.tableView reloadData]; // this will call the datasource which will call the lazy getter
}

答案 1 :(得分:0)

你正试图在它的界限之外读入一个数组。

该阵列访问看起来非常可疑

if (indexPath.row % 2 == 0)  {
    NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];

以及这个

NSDictionary *entry = [self entries][indexPath.row];

从我看到的数组tweets[self entries]中,每个对象都不包含与表格部分中的行一样多的对象。

我从这里接受了我的意见:

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

答案 2 :(得分:0)

抛出

NSRangeException是因为您尝试访问的索引不在数组的有效范围内。尝试在Xcode中设置“异常断点”以查看它的来源。检查here以了解有关异常断点的更多信息

这通常是由 off by one 错误引起的。