UITableView dataSource 对象在滚动时变为空

Posted

技术标签:

【中文标题】UITableView dataSource 对象在滚动时变为空【英文标题】:UITableView dataSource objects become null when scroll 【发布时间】:2015-11-12 19:41:55 【问题描述】:

我是CoreData 的新手,并使用MagicalRecord 来管理它。我的问题是我将UITableViewNSArray 作为数据源填充了从CoreData db 获取的对象,并且在我滚动表格一段时间之前一切似乎都很好。

这是我的代码:

获取数据的方法(MyDatabase.m):

+(NSArray *)getEntities
   ...

return [MyEntity MR_findAllSortedBy:@"name" ascending:YES withPredicate:predicate];

以下是我在 ViewController 中获取数据并将其设置为 UITableView 的方法:

- (void)viewDidLoad 
   [super viewDidLoad];

   myEntitiesArray = [MyDatabase getEntities];

   if(myEntitiesArray.count != 0)
      [myTableView setTableData:myEntitiesArray];

这里是 MyTableView.m 中的setTableData 方法实现:

- (void)setTableData:(NSArray *)array 
   if (array && [array count] > 0) 
      _tableData = array;
      [self reloadData];
   

下面是我在 MyTableView.m 中设置单元格的方式:

- (void)tableView:(UITableView *)tableView willDisplayCell:(SSCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 

   cell.nameLabel.text = [(MyEntity *)_tableData[indexPath.row] name];


我尝试将NSLog(@"name is %@",[(MyEntity *)_tableData[indexPath.row] name]) 放入willDisplayCell 并发现当单元格为空时,NSLog 会打印出消息“名称为(空)”。在我遇到这个问题之前,我知道这个问题可能已经被很多人多次解决了。希望有人也能帮助我解决它:)

更新:cellForRowAtIndexPath 方法:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  static NSString *cellIdentifier = @"ssCell";
  SSCell *cell = (SSCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
  if( !cell ) 
      [self registerNib:[UINib nibWithNibName:@"SSCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
      cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
      [cell setSelectedBackgroundView:selectedBackgroundView];

  cell.nameLabel.text = [(MyEntity *)_tableData[indexPath.row] name];
  return cell;

我也在MyTableView.minit方法里面调用了这个方法:

[self registerNib:[UINib nibWithNibName:@"SSCell" bundle:nil] forCellReuseIdentifier:@"ssCell"];

【问题讨论】:

你的 cellForRowAtIndexPath 方法在哪里?我认为当你必须使用 cellForRowAtIndexPath 时你正在使用 willDisplayCell @CCastro 看到我的更新,我将线路从 willDisplayCell 移到 cellForRowAtIndexPath 并且没有运气 更改此单元格 = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];对于这个单元格 = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 我想知道以下哪个是 nil:tableData、tableData[indexPath.row]、名称甚至单元格。创建单元格的嵌套初始化是否可能失败? 使用 MR 而不是 FRC 应该会自动删除您的 SO 帐户。有多少问题涉及 MR 和由数组支持的 UITableView,这太疯狂了。只是说... 【参考方案1】:

您必须使用 cellForRowAtIndexPath。在这种方法中,单元被分配。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    /*
     *   This is an important bit, it asks the table view if it has any available cells
     *   already created which it is not using (if they are offscreen), so that it can
     *   reuse them (saving the time of alloc/init/load from xib a new cell ).
     *   The identifier is there to differentiate between different types of cells
     *   (you can display different types of cells in the same table view)
     */

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];

    /*
     *   If the cell is nil it means no cell was available for reuse and that we should
     *   create a new one.
     */

    if (cell == nil) 

        /* 
        *   Actually create a new cell (with an identifier so that it can be dequeued). 
        */

            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"];
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
     

    /*
     *   Now that we have a cell we can configure it to display the data corresponding to
     *   this row/section
     */

      cell.nameLabel.text = [(MyEntity *)_tableData[indexPath.row] name];
    return cell;
 

【讨论】:

【参考方案2】:

您应该通过调用 init.相反,您正在执行以下操作:

如果(!细胞) [self registerNib:[UINib nibWithNibName:@"SSCell" bundle:nil] forCellReuseIdentifier:cellIdentifier]; 单元格 = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; [单元格setSelectedBackgroundView:selectedBackgroundView];

当没有可用的单元格时,第二次调用尝试再次重用现有单元格。那可能会再次返回 nil。

要非常小心目标 C 的“特性”,调用 nil 对象的方法什么都不做。它不会像 Java 那样因 null.pointer.exception 而崩溃,它可能会漂浮在 [cell setSelectedBackgroundView:selectedBackgroundView] 和一大堆其他行上而没有问题。

【讨论】:

我知道UITableView 不会因为重复使用而为每一行创建UITableViewCell。我创建了我的单元格并在cellForRowAtIndexPath 中重复使用它,单元格本身没有问题。我的数组中的对象有问题。附言试图将线路移动到cellForRowAtIndexPath,但运气不好:(

以上是关于UITableView dataSource 对象在滚动时变为空的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 在 tableview.datasource 开始时崩溃

一行代码,快速为UITableView创建Delegate和DataSource

UITableView 仅用于 GUI 控件,没有 DataSource

UITableView dataSource 必须从 tableView:cellForRowAtIndexPath 返回一个单元格

在 ViewController 中使用带有外部 DataSource 和 UITableView 的自定义 UITableViewCell

如何在 UITableview DataSource 方法中的 UIContextualAction 中添加图像