Background
我有一个处理 2 个UITableView
的UIViewController
,两者都带有自定义UITableViewCell
子类。顶部表(类别)上的单击事件应该触发底部表(RSS 源中的文章列表)上的reloadData
,具体取决于选择的类别。应该发生的是拉取新数据并重新填充相关数组,然后数据显示在底部表上。
要显示的数据是:
- 一张图片
- a
UILabel
(日期) - 标题的
UITextView
1)第一个问题
启动应用程序时默认加载的列表可以正确加载(几乎,但我在 #2 中得到了"几乎"),但是一旦在顶部表中选择了类别,包含要在单元格中显示的数据的数组将使用相关数据重建,但 reloadData
方法不会立即调用所需的结果。只有向下滚动一次,然后向上滚动,新数据显示。使用调试,我可以看到数据被正确加载到数组中,所以我确定这是一个UITableViewController
或UITableViewCell
的问题。
我已经尝试了在StackOverflow上讨论的各种解决方案,除了明显的self.myTableView.reloadData
最常见的两个是调用ReloadData,如下所示:
[self.myTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
还有
dispatch_async(dispatch_get_main_queue(), ^{
[self.myTableView reloadData];});
}
每次我尝试从 ArticlesTableViewController 实例中调用这些时,都没有成功。
2)第二个问题
DateLabel 仅在打开应用程序时显示在第一个单元格上,然后要使 dateLabel 显示在其余单元格中,我实际上必须向下滚动,然后再次向上滚动。从上方返回视图的单元格包含 dateLabel,但如果单元格从下方重新出现在视图中,则它再次消失。非常令人困惑的东西。
这是我的相关代码
cellForRowAtIndexPath
(ArticlesTableViewController
):
// Method that gets fired when parsing is complete via NSNotification
- (void) parsingComplete {
//Tell the tableview to animate the changes automatically
self.articleList = [[NSMutableArray alloc]initWithArray:parser.articles];
[myTableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
ArticlesTableViewCell *cell = (ArticlesTableViewCell *)[myTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!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(), ^{
cell.enclosure.image = image;
[cell.enclosure setNeedsDisplay];
});
}
}
});
[cell.dateLabel setText:[[self.articleList valueForKey:@"pubDate"] objectAtIndex:indexPath.row]];
[cell.headingTextView setText:[[self.articleList valueForKey:@"title"] objectAtIndex:indexPath.row]];
cell.headingTextView.editable = NO;
return cell;
}
自定义单元格代码(用于ArticlesTableViewCell
):
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.enclosure = [[UIImageView alloc] initWithFrame:CGRectMake(10,10,48,48)];
self.enclosure.tag = 1;
//self.imageView = nil;
self.dateLabel = [[UILabel alloc] initWithFrame: CGRectMake (75,-10,50,50)];
self.dateLabel.textColor = [UIColor grayColor];
self.dateLabel.font = [UIFont fontWithName:@"Arial" size:8.0f];
self.headingTextView= [[UITextView alloc] initWithFrame:CGRectMake(70, 20, 400, 80)];
self.headingTextView.textColor = [UIColor blackColor];
self.headingTextView.font = [UIFont fontWithName:@"Arial" size:10.0f];
[self addSubview:self.dateLabel];
[self addSubview:self.enclosure];
[self addSubview:self.headingTextView];
//Here the Date only appears in the first cell, but when I scroll down and up again it re-appears
}
return self;
}
编辑下面是CategoriesTableViewController
(第一个表)中的CellForRowAtIndexPath
代码:
- (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;
}
下面是 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;
}