UITableView cellForRowAtIndexPath被提前调用

时间:2022-08-23 11:37:54

I have a UITableView that loads its array items fine on the first call. However when i refresh the tableview it crashes because the delegate method cellForRowAtIndexPath gets called to early. I have an integer which represents the index of my main data array and this gets reset to 0 in my refresh button. However its crashing because its trying to reload the data before its been reset. I would normally use indexPath.row as my index however the array is complicated and the indexPath.row will not match up to what i want to show for each cell. Heres some code, any help is appreciated.

我有一个UITableView,可以在第一次调用时加载其数组项。但是,当我刷新tableview时它会崩溃,因为委托方法cellForRowAtIndexPath被提前调用。我有一个整数,表示我的主数据数组的索引,并在我的刷新按钮中重置为0。然而它崩溃是因为它试图在重置之前重新加载数据。我通常会使用indexPath.row作为我的索引,但是数组很复杂,而indexPath.row与我想为每个单元格显示的内容不匹配。下面是一些代码,任何帮助表示赞赏。

This gets called when i pull down to refresh AND in viewDidLoad to prepare the data

当我在viewDidLoad中下拉刷新AND以准备数据时,会调用此方法

- (IBAction)refresh:(id)sender {
itemIndexer = 0;
[sender beginRefreshing];
[self loadData];
}

Part of my loadData method

我的loadData方法的一部分

-(void) loadData {
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.Foo.myqueue", 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();

dispatch_async(backgroundQueue, ^{

   [self downloadData];

    dispatch_async(mainQueue, ^{
            [self.tableView reloadData];
            [_rcRefresh endRefreshing];
    });
});

In viewDidLoad i call to initially load the tableview:

在viewDidLoad中,我调用最初加载tableview:

[self refresh:_rcRefresh];

I am getting a index outside bounds of array error. Which i have used breakpoints to determine why, the reason is simply because the refresh isn't getting called at all otherwise itemIndexer would be set to 0. Instead its a number 1 greater than the array size. If its really necessary i can post cellForRowAtIndexPath however I'm unsure if you need it if it works on the first call. So to summarise the first call to the tableview works and the data is loaded fine however the refresh causes the index to be outside the bounds of the array as if refresh: is never called.

我得到一个超出数组错误范围的索引。我使用断点来确定原因,原因仅仅是因为刷新没有被调用,否则itemIndexer将被设置为0.而是比数组大小大1。如果它真的有必要我可以发布cellForRowAtIndexPath但是我不确定你是否需要它,如果它在第一次调用时工作。因此,总结对tableview的第一次调用是有效的,并且数据加载正常,但刷新会导致索引超出数组的边界,就像从不调用refresh:一样。

2 个解决方案

#1


4  

For what you say, I can only try guessing:

对于你说的,我只能猜测:

  • Your numberOfSectionsInTableView/numberOfRowsInSection is returning a wrong number.

    您的numberOfSectionsInTableView / numberOfRowsInSection返回错误的数字。

  • If [self downloadData] is asynchronous (you are making a server request and not waiting for the response), you should reloadData once you have the data.

    如果[self downloadData]是异步的(您正在发出服务器请求而不是等待响应),则应在获得数据后重新加载数据。

  • The data you download is not merged properly with the data you already have.

    您下载的数据未与您已有的数据正确合并。

Some more code (numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath, downloadData) would definitely help.

一些更多的代码(numberOfSectionsInTableView,numberOfRowsInSection,cellForRowAtIndexPath,downloadData)肯定会有所帮助。

#2


2  

Couple of points for clarity...

几点清晰......

  • As indicated by @k20, it is not that tableView:cellForRowAtIndexPath: is called too early, but that you need to better manage your download data once your asynchronous process / method has completed.
  • 正如@ k20所示,不是tableView:cellForRowAtIndexPath:被调用得太早,但是一旦异步过程/方法完成,您需要更好地管理下载数据。

  • tableView:cellForRowAtIndexPath: is a UITableView data source method, not a delegate method. It is worth mentioning this pedantic detail because it may help you or others better understand the code you are writing. ;)
  • tableView:cellForRowAtIndexPath:是一个UITableView数据源方法,而不是委托方法。值得一提的是这个迂腐的细节,因为它可以帮助您或其他人更好地理解您正在编写的代码。 ;)

The table view method calls are what they are - as I understand it, all table view methods are called in order, each time a UITableViewController is init or awakeFromNib. Those that you must override (tableView:numberOfRowsInSection: & tableView:cellForRowAtIndexPath:), and those that you choose to override will still execute in that same order.

表视图方法调用就是它们 - 据我所知,每次UITableViewController是init或awakeFromNib时,所有表视图方法都按顺序调用。您必须覆盖的那些(tableView:numberOfRowsInSection:&tableView:cellForRowAtIndexPath :),以及您选择覆盖的那些仍将以相同的顺序执行。

Therefore a more appropriate title for your question might be... "How to update a UITableView with data from a download on an asynchronous thread."

因此,对于您的问题,更合适的标题可能是......“如何使用异步线程上的下载数据更新UITableView。”

Again @k20 is pointing you to the correct solution. Have you attempting placing these two lines of code...

再次@ k20指向您正确的解决方案。您是否尝试过这两行代码......

        [self.tableView reloadData];
        [_rcRefresh endRefreshing];

within your async call, instead of back in the main queue?

你的异步调用中,而不是回到主队列?

It may be that your code as written is executing like this...

可能是您编写的代码正在执行这样的...

  1. Prepare local variables for dispatch_q_t;
  2. 为dispatch_q_t准备局部变量;

  3. Commence download process;
  4. 开始下载过程;

  5. reload data for table view;
  6. 重新加载表视图的数据;

  7. end the refresh [_rcRefresh endRefreshing];
  8. 刷新[_rcRefresh endRefreshing];

  9. depending on time it takes, then finish download process;
  10. 取决于所需的时间,然后完成下载过程;

Where you obviously would like to execute like this...

你明显想要这样执行的地方......

  1. Prepare local variables for dispatch_q_t;
  2. 为dispatch_q_t准备局部变量;

  3. Commence download process;
  4. 开始下载过程;

  5. depending on time it takes, finish download process;
  6. 根据时间,完成下载过程;

  7. reload data for table view;
  8. 重新加载表视图的数据;

  9. end the refresh [_rcRefresh endRefreshing];
  10. 刷新[_rcRefresh endRefreshing];

Try my suggestion and let me know how you go. Hope that helps.

试试我的建议,让我知道你怎么走。希望有所帮助。

#1


4  

For what you say, I can only try guessing:

对于你说的,我只能猜测:

  • Your numberOfSectionsInTableView/numberOfRowsInSection is returning a wrong number.

    您的numberOfSectionsInTableView / numberOfRowsInSection返回错误的数字。

  • If [self downloadData] is asynchronous (you are making a server request and not waiting for the response), you should reloadData once you have the data.

    如果[self downloadData]是异步的(您正在发出服务器请求而不是等待响应),则应在获得数据后重新加载数据。

  • The data you download is not merged properly with the data you already have.

    您下载的数据未与您已有的数据正确合并。

Some more code (numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath, downloadData) would definitely help.

一些更多的代码(numberOfSectionsInTableView,numberOfRowsInSection,cellForRowAtIndexPath,downloadData)肯定会有所帮助。

#2


2  

Couple of points for clarity...

几点清晰......

  • As indicated by @k20, it is not that tableView:cellForRowAtIndexPath: is called too early, but that you need to better manage your download data once your asynchronous process / method has completed.
  • 正如@ k20所示,不是tableView:cellForRowAtIndexPath:被调用得太早,但是一旦异步过程/方法完成,您需要更好地管理下载数据。

  • tableView:cellForRowAtIndexPath: is a UITableView data source method, not a delegate method. It is worth mentioning this pedantic detail because it may help you or others better understand the code you are writing. ;)
  • tableView:cellForRowAtIndexPath:是一个UITableView数据源方法,而不是委托方法。值得一提的是这个迂腐的细节,因为它可以帮助您或其他人更好地理解您正在编写的代码。 ;)

The table view method calls are what they are - as I understand it, all table view methods are called in order, each time a UITableViewController is init or awakeFromNib. Those that you must override (tableView:numberOfRowsInSection: & tableView:cellForRowAtIndexPath:), and those that you choose to override will still execute in that same order.

表视图方法调用就是它们 - 据我所知,每次UITableViewController是init或awakeFromNib时,所有表视图方法都按顺序调用。您必须覆盖的那些(tableView:numberOfRowsInSection:&tableView:cellForRowAtIndexPath :),以及您选择覆盖的那些仍将以相同的顺序执行。

Therefore a more appropriate title for your question might be... "How to update a UITableView with data from a download on an asynchronous thread."

因此,对于您的问题,更合适的标题可能是......“如何使用异步线程上的下载数据更新UITableView。”

Again @k20 is pointing you to the correct solution. Have you attempting placing these two lines of code...

再次@ k20指向您正确的解决方案。您是否尝试过这两行代码......

        [self.tableView reloadData];
        [_rcRefresh endRefreshing];

within your async call, instead of back in the main queue?

你的异步调用中,而不是回到主队列?

It may be that your code as written is executing like this...

可能是您编写的代码正在执行这样的...

  1. Prepare local variables for dispatch_q_t;
  2. 为dispatch_q_t准备局部变量;

  3. Commence download process;
  4. 开始下载过程;

  5. reload data for table view;
  6. 重新加载表视图的数据;

  7. end the refresh [_rcRefresh endRefreshing];
  8. 刷新[_rcRefresh endRefreshing];

  9. depending on time it takes, then finish download process;
  10. 取决于所需的时间,然后完成下载过程;

Where you obviously would like to execute like this...

你明显想要这样执行的地方......

  1. Prepare local variables for dispatch_q_t;
  2. 为dispatch_q_t准备局部变量;

  3. Commence download process;
  4. 开始下载过程;

  5. depending on time it takes, finish download process;
  6. 根据时间,完成下载过程;

  7. reload data for table view;
  8. 重新加载表视图的数据;

  9. end the refresh [_rcRefresh endRefreshing];
  10. 刷新[_rcRefresh endRefreshing];

Try my suggestion and let me know how you go. Hope that helps.

试试我的建议,让我知道你怎么走。希望有所帮助。