【问题标题】:Application crashes after parsing when scrolling uitableview滚动uitableview时解析后应用程序崩溃
【发布时间】:2016-08-28 11:25:07
【问题描述】:

请查看我的代码。应用程序工作正常,但是当我快速向上或向下滚动时它就会崩溃。

* 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“* -[__NSArrayM objectAtIndex:]:索引 0 超出范围 空数组'

这里是cellforrawatindexpath方法

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

        UITableViewCell *cell = (UITableViewCell *)[self.messageList dequeueReusableCellWithIdentifier:@"ChatListItem"];
        if (cell == nil) {
            NSArray *nib;
            if ([[[rssOutputData objectAtIndex:indexPath.row] xml_userType] isEqualToString:@"2"])// THIS IS THE LINE WHERE IT CRASHES
 {
                nib = [[NSBundle mainBundle] loadNibNamed:@"OutGoing" owner:self options:nil];
                textLabel =[[UILabel alloc] initWithFrame:CGRectMake(58,12,241,30 )];

                cell.textLabel.textAlignment = NSTextAlignmentLeft;

            }else {
                nib = [[NSBundle mainBundle] loadNibNamed:@"InComing" owner:self options:nil];
                textLabel =[[UILabel alloc] initWithFrame:CGRectMake(21,12,241,30)];
                cell.textLabel.textAlignment = NSTextAlignmentRight;
            }
            cell = (UITableViewCell *)[nib objectAtIndex:0];
        }
        textLabel = (UILabel *)[cell viewWithTag:1];
        userLabel = (UILabel *)[cell viewWithTag:2];
        avatar = (UIImageView *)[cell viewWithTag:3];
        timeLabel = (UILabel *)[cell viewWithTag:4];

        NSString * test=[[rssOutputData objectAtIndex:indexPath.row]xml_msg];
        textLabel.text = test;
        textLabel.numberOfLines = 0; 
        [textLabel sizeToFit];
        [cell addSubview:textLabel];
        userLabel.text = [[rssOutputData objectAtIndex:indexPath.row]xml_username];

        avatar.layer.cornerRadius = 20.0;
        avatar.layer.masksToBounds = YES;
        if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"patient_name"] isEqualToString:[[rssOutputData objectAtIndex:indexPath.row]xml_username]] || [[[NSUserDefaults standardUserDefaults] stringForKey:@"therapist"] isEqualToString:[[rssOutputData objectAtIndex:indexPath.row]xml_username]]) {
            avatar.image = [UIImage imageNamed:@"p.jpg"];
        }else {
            avatar.image = [UIImage imageNamed:@"t.jpg"];
        }
        rectTime = (CGRect){0, textLabel.frame.size.height+5, 241, 11};
        timeLabel = [[UILabel alloc] initWithFrame:rectTime];
        timeLabel.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
        timeLabel.text = [[rssOutputData objectAtIndex:indexPath.row]xml_addedTime];
        timeLabel.backgroundColor = [UIColor clearColor];
        timeLabel.textColor = [UIColor lightGrayColor];
        [textLabel addSubview:timeLabel];

        return cell;
    }

实际上,我正在从每 5 秒调用一次的 xml 文件中加载数据。我将在这里发布我的解析代码。

- (void) Parse{
        previusCount = rssOutputData.count;
        rssOutputData = [[NSMutableArray alloc]init];
        NSString *post =[[NSString alloc] initWithFormat:@"https://messages_%@.xml",[[NSUserDefaults standardUserDefaults] stringForKey:@"xmls_id"]];
           dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0),^{

            NSData *xmlData=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:post]];
            xmlParserObject =[[NSXMLParser alloc]initWithData:xmlData];
            [xmlParserObject setDelegate:self];
            [xmlParserObject parse];

            dispatch_async(dispatch_get_main_queue(), ^{
                [messageList reloadData];
            });
        });
}

这是来自 ViewDidLoad 的 NSTIMER

 timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target: self selector: @selector(Parse) userInfo: nil repeats: YES];

下面是其余的解析代码

#pragma mark NSXMLParser delegate
//below delegate method is sent by a parser object to provide its delegate when it encounters a start tag
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
    if([elementName isEqualToString:@"message"]){
        xmlStringFileObject =[[XMLChatFile alloc]init];
    } else {
        nodecontent = [[NSMutableString alloc] init];
    }
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [nodecontent appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if([elementName isEqualToString:@"message"]){
        [rssOutputData addObject:xmlStringFileObject];
        xmlStringFileObject = nil;
    }
    else if([elementName isEqualToString:@"added"]){
        xmlStringFileObject.xml_addedTime= nodecontent;
        nodecontent = nil;
    }
    else if([elementName isEqualToString:@"user"]){
        xmlStringFileObject.xml_username= nodecontent;
        nodecontent = nil;
    }
    else if([elementName isEqualToString:@"text"]){
        xmlStringFileObject.xml_msg= nodecontent;
        nodecontent = nil;
    }
    else if([elementName isEqualToString:@"user_type"]){
        xmlStringFileObject.xml_userType= nodecontent;
        nodecontent = nil;
    }
}

【问题讨论】:

  • 崩溃信息是什么?
  • *** 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array”
  • 这是因为您将 nil 值设置为 UILabel 或任何其他控件。检查 nil 对象并设置为空字符串。
  • 我这样做了,但仍然是同样的错误。

标签: ios objective-c uitableview xml-parsing nsxmlparser


【解决方案1】:

是的,很明显,您正在尝试访问其中一个数组中不存在的元素。

问题:如果你在 Xcode 中“启用僵尸”然后重新运行你的代码,它会告诉你是哪一行导致了问题吗?

Enable zombies in Xcode

从那里,您应该能够找到原因。

您也可以尝试在 cellForRowAtIndexPath 函数的顶部粘贴这样的内容...

if (rssOutputData == nil)
    return;
if (rssOutputData.count <= objectAtIndex:indexPath.row)
    return;

...但我仍然认为这个问题是由您的 UITableView 尝试(快速)加载和显示数据引起的,而您的 5 秒函数正忙于清空然后刷新。

毕竟,每 5 秒 函数正在清空您的数组,然后等待 使用网络服务重新填充它。

在该网络服务完成之前,您的 UITableView 将绑定到其中没有数据的数据源...这不正常!!

    rssOutputData = [[NSMutableArray alloc]init];
    NSString *post =[[NSString alloc] initWithFormat:@"https://messages_%@.xml",
        [[NSUserDefaults standardUserDefaults] stringForKey:@"xmls_id"]];
   ... load data from this web service...

难怪滚动时它会崩溃......

顺便说一句,在您的 Parse 函数中,您在哪里将 rssOutputData 值设置为您刚刚从 Web 服务加载的任何内容...?

【讨论】:

  • 我禁用了计时器代码,之后该应用程序不再崩溃,但如果我这样做了,如果它在服务器上更新,我将如何刷新 xml 和消息!
  • 看我的最后一句话:现在,你的 Parse 函数“清空”了你绑定的数组......但你似乎再也没有填充它......?基本上,我看不到“rssOutputData”在哪里设置......
  • 我用其余代码更新了我的问题。请查看
  • 我看过了!但是,我的评论保持不变。你有一个 UITableView 显示,比如 100 条记录。您的 Parse 函数清空此数组(在此期间您可以继续滚动 tableview 并且它会崩溃,因为这些项目不再存在)并且 UITableView 的数据源在该 Web 服务完成之前不会再次获取任何数据。要了解我的意思,请在清空“rssOutputData”数组的 Parse 行之后立即添加 [messageList reloadData]。然后,您将看到您的表格可以随时查看的真实数据量......
  • 是的,你是对的,这就是大多数情况下实际发生的情况,或者我应该说每次滚动时都会崩溃。那么我能做些什么来防止它呢?如果我不使用计时器,我如何更新条目!谢谢你的时间。
【解决方案2】:

您的 rssOutputData 似乎为空或低于 numberOfRows。

看到你使用 rssOutputData,然后你重置它:

// ...
previusCount = rssOutputData.count;
rssOutputData = [[NSMutableArray alloc]init]; 
// ...

并且在您共享的代码中,您不会再次为其设置任何值。

【讨论】:

  • 你能告诉我如何设置它的值!将不胜感激
  • 是的,实际上我正在保存其先前的计数以比较计数是否有任何增加。保存该 rssOutputData.count 后重置它以从 xml 获取新值。
  • 这是 [xmlParserObject 解析];退货?因此,查看您的代码,您必须为 rssOutputData 设置一个 XML 对象数组。如果 [xmlParserObject parse] 一直在返回 XML 对象数组,您可以这样做: rssOutputData = [[NSMutableArray alloc] initWithArray:[xmlParserObject parse]];
  • 那么你在哪里重置 rssOutputData?可以分享一下代码吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-21
  • 2012-12-07
  • 1970-01-01
  • 2018-01-16
  • 2011-07-10
  • 2011-12-26
  • 1970-01-01
相关资源
最近更新 更多