Ios UITableView数据仅在我滚动时重新加载(带有bug),并且我无法正确地重新加载数据 出身背景
我有一个Ios UITableView数据仅在我滚动时重新加载(带有bug),并且我无法正确地重新加载数据 出身背景,ios,objective-c,uitableview,Ios,Objective C,Uitableview,我有一个UIViewController,它处理2个UITableViews,这两个都带有自定义的UITableViewCell子类。顶部表格(类别)上的单击事件应触发底部表格(RSS提要中的文章列表)上的重新加载数据,具体取决于选择的类别。应该发生的是提取新数据并重新填充相关数组,然后数据显示在底部表格中 要显示的数据是: 形象 aui标签(用于日期) 标题的UITextView 1) 第一个问题 启动应用程序时默认加载的列表会正确加载(很好,但我会进入#2中的“几乎”),但一旦在顶部表格
UIViewController
,它处理2个UITableView
s,这两个都带有自定义的UITableViewCell
子类。顶部表格(类别)上的单击事件应触发底部表格(RSS提要中的文章列表)上的重新加载数据,具体取决于选择的类别。应该发生的是提取新数据并重新填充相关数组,然后数据显示在底部表格中
要显示的数据是:
- 形象
- a
ui标签
(用于日期)
- 标题的
UITextView
1) 第一个问题
启动应用程序时默认加载的列表会正确加载(很好,但我会进入#2中的“几乎”),但一旦在顶部表格中选择了一个类别,包含要在单元格中显示的数据的数组将使用相关数据重建,但是reloadData
方法不会立即调用所需的结果。只有向下滚动一次,然后再向上滚动,新数据才会显示。通过调试,我可以看到数据被正确加载到数组中,因此我确信这是一个UITableViewController
或UITableViewCell
问题
除了显而易见的self.myTableView.reloadData
调用reloadData这两种最常见的方法外,我还尝试了这里讨论的StackOverflow的各种解决方案,如下所示:
[self.myTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
而且
dispatch_async(dispatch_get_main_queue(), ^{
[self.myTableView reloadData];});
}
每次我试图从ArticlesTableViewController实例中调用这些,都没有成功
2) 第二个问题
DateLabel仅在打开应用程序时显示在第一个单元格中,然后DateLabel显示在其余单元格中,我实际上必须向下滚动,然后再向上滚动。从上方返回视图的单元格包含日期标签,但如果从下方返回视图的单元格再次消失。相当混乱的东西
这是我的相关代码
cellforrowatinexpath
(在文章StableViewController
中):
自定义单元格代码(对于ArticleStableWicell
):
编辑
下面是分类表视图控制器
中的单元格行索引路径
代码(第一个表):
下面是ViewController中实例化这两个TableViewController的代码:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *categoryView = [[UIView alloc] init];
[categoryView setFrame:CGRectMake(60,0, 100,-200)];
UIView *articlesView = [[UIView alloc] init];
[articlesView setFrame:CGRectMake(0,50, 400,400)];
CatBarTVC *categoryBar = [[CatBarTVC alloc] initWithStyle:UITableViewStylePlain];
categoryBar.view.transform = CGAffineTransformMakeRotation(-M_PI * 0.5);
categoryBar.view.autoresizesSubviews=NO;
ArticlesTVC *articles = [[ArticlesTVC alloc] initWithStyle:UITableViewStylePlain];
[articlesView addSubview:articles.view];
//[self addChildViewController:articles];
//[articlesView addSubview:articles.view];
[self.view addSubview:categoryBar.view];
[self.view addSubview:articles.view];
[self addChildViewController:categoryBar];
[self addChildViewController:articles];
categoryBar.view.frame =CGRectMake(0,0, 500,70);
articles.view.frame =CGRectMake(0,50, 400,400);
}
我在代码中看到了许多问题。请查看代码中的注释:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Suggestion: Try to keep identifier in ArticlesTableViewCell if you want to use it in more than one table view controller. Don't use _tableView. _tableView is iVar. You should use it only in getters, setters and in init methods.
static NSString *CellIdentifier = @"Cell";
// Don't call "self.myTableView" of one specific tableView but for current one that is apassed by argument (tableView).
ArticlesTableViewCell *cell = (ArticlesTableViewCell *)[self.myTableView dequeueReusableCellWithIdentifier:CellIdentifier];
// You override here existing cell. Try to use if(cell==nil) before creating new cell.
cell = [[ArticlesTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[self.articleList valueForKey:@"enclosure"] objectAtIndex:indexPath.row]]];
if (imgData) {
UIImage *image = [UIImage imageWithData:imgData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
// You should call [cell setNeedsDisplay to inform app that this view have to be redrawn.
cell.enclosure.image = image;
});
}
}
});
// No need to call this on global quele. You should call this directly (e.g. cell.dataLabel = self.articleList[@"pubDate"][indexpath.row];)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cell.dateLabel performSelectorOnMainThread:@selector(setText:) withObject:[[self.articleList valueForKey:@"pubDate"] objectAtIndex:indexPath.row] waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
[cell.headingTextView performSelectorOnMainThread:@selector(setText:) withObject:[[self.articleList valueForKey:@"title"] objectAtIndex:indexPath.row] waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
cell.headingTextView.editable = NO;
});
return cell;
}
您说您有两个UITableView,但我看不出您的代码将它们区分开来。每个UItableview都应该有自己的出口。我已经用相关代码更新了我的帖子。在同一个视图控制器中是否有两个-(UITableViewCell*)tableView:(UItableview*))tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
?这是行不通的,操作系统如何知道哪一个与我编辑过的表相关?为了清楚起见,这些代码段属于单独的TableViewController类。好吧,如果您使用的是UITableViewController而不是UITableView,然后UITableViewController负责每个tableView的数据源和委托,而不是UIViewController。因此,任何重新加载数据源的调用(即重新加载UITableView的数据)都应该在UITableViewController中进行,而不是在UIViewControllerI中进行相应的更改。谢谢你能谈谈你对IVAR的第一次评论吗?我做了正确的更改了吗?不要使用self.myTableView
尽可能使用tableView
(例如在cellforrowatinexpath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
CatTableViewCell *cell = (CatTableViewCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CatTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.nameLabel.text = [categories objectAtIndex:indexPath.row];
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIView *categoryView = [[UIView alloc] init];
[categoryView setFrame:CGRectMake(60,0, 100,-200)];
UIView *articlesView = [[UIView alloc] init];
[articlesView setFrame:CGRectMake(0,50, 400,400)];
CatBarTVC *categoryBar = [[CatBarTVC alloc] initWithStyle:UITableViewStylePlain];
categoryBar.view.transform = CGAffineTransformMakeRotation(-M_PI * 0.5);
categoryBar.view.autoresizesSubviews=NO;
ArticlesTVC *articles = [[ArticlesTVC alloc] initWithStyle:UITableViewStylePlain];
[articlesView addSubview:articles.view];
//[self addChildViewController:articles];
//[articlesView addSubview:articles.view];
[self.view addSubview:categoryBar.view];
[self.view addSubview:articles.view];
[self addChildViewController:categoryBar];
[self addChildViewController:articles];
categoryBar.view.frame =CGRectMake(0,0, 500,70);
articles.view.frame =CGRectMake(0,50, 400,400);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Suggestion: Try to keep identifier in ArticlesTableViewCell if you want to use it in more than one table view controller. Don't use _tableView. _tableView is iVar. You should use it only in getters, setters and in init methods.
static NSString *CellIdentifier = @"Cell";
// Don't call "self.myTableView" of one specific tableView but for current one that is apassed by argument (tableView).
ArticlesTableViewCell *cell = (ArticlesTableViewCell *)[self.myTableView dequeueReusableCellWithIdentifier:CellIdentifier];
// You override here existing cell. Try to use if(cell==nil) before creating new cell.
cell = [[ArticlesTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[self.articleList valueForKey:@"enclosure"] objectAtIndex:indexPath.row]]];
if (imgData) {
UIImage *image = [UIImage imageWithData:imgData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
// You should call [cell setNeedsDisplay to inform app that this view have to be redrawn.
cell.enclosure.image = image;
});
}
}
});
// No need to call this on global quele. You should call this directly (e.g. cell.dataLabel = self.articleList[@"pubDate"][indexpath.row];)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cell.dateLabel performSelectorOnMainThread:@selector(setText:) withObject:[[self.articleList valueForKey:@"pubDate"] objectAtIndex:indexPath.row] waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
[cell.headingTextView performSelectorOnMainThread:@selector(setText:) withObject:[[self.articleList valueForKey:@"title"] objectAtIndex:indexPath.row] waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
cell.headingTextView.editable = NO;
});
return cell;
}