滚动 uitableview 时应用程序在解析后崩溃
Application crashes after parsing when scrolling uitableview
请查看我的代码。应用程序工作正常,但当我快速向上或向下滚动时,它就会崩溃。
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for
empty array'
这里是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 文件加载数据。我将 post 我的解析代码放在这里。
- (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;
}
}
您的 rssOutputData 似乎为空或小于 numberOfRows。
看到你使用 rssOutputData,然后你重置它:
// ...
previusCount = rssOutputData.count;
rssOutputData = [[NSMutableArray alloc]init];
// ...
并且在您共享的代码中,您没有再次为其设置任何值。
是的,显而易见的是,您正试图访问一个数组中不存在的元素。
问题:如果您在 Xcode 中 "enable zombies" 然后重新 运行 您的代码,它会告诉您是哪一行导致了问题吗?
Enable zombies in Xcode
从那里,您应该能够找到原因。
您也可以尝试在 cellForRowAtIndexPath
函数的顶部添加类似这样的内容...
if (rssOutputData == nil)
return;
if (rssOutputData.count <= objectAtIndex:indexPath.row)
return;
...但我仍然认为这个问题是由您的 UITableView
试图(快速)加载和显示数据引起的,您的 5 秒函数正忙于清空然后刷新。
毕竟,每 5 秒 函数正在清空您的数组,然后等待 使用 Web 服务重新填充它。
直到该 Web 服务 完成 ,您的 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 服务加载的值...?
请查看我的代码。应用程序工作正常,但当我快速向上或向下滚动时,它就会崩溃。
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
这里是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 文件加载数据。我将 post 我的解析代码放在这里。
- (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;
}
}
您的 rssOutputData 似乎为空或小于 numberOfRows。
看到你使用 rssOutputData,然后你重置它:
// ...
previusCount = rssOutputData.count;
rssOutputData = [[NSMutableArray alloc]init];
// ...
并且在您共享的代码中,您没有再次为其设置任何值。
是的,显而易见的是,您正试图访问一个数组中不存在的元素。
问题:如果您在 Xcode 中 "enable zombies" 然后重新 运行 您的代码,它会告诉您是哪一行导致了问题吗?
Enable zombies in Xcode
从那里,您应该能够找到原因。
您也可以尝试在 cellForRowAtIndexPath
函数的顶部添加类似这样的内容...
if (rssOutputData == nil)
return;
if (rssOutputData.count <= objectAtIndex:indexPath.row)
return;
...但我仍然认为这个问题是由您的 UITableView
试图(快速)加载和显示数据引起的,您的 5 秒函数正忙于清空然后刷新。
毕竟,每 5 秒 函数正在清空您的数组,然后等待 使用 Web 服务重新填充它。
直到该 Web 服务 完成 ,您的 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 服务加载的值...?