简体   繁体   English

调用reloadData后出现UITableView性能问题

[英]UITableView performance issue after calling reloadData

I'm an Android developer working on my first iOS project. 我是一名Android开发人员,负责我的第一个iOS项目。 I have a UITableView that displays almost 37,500 rows. 我有一个显示近37,500行的UITableView。 One row for each item in an grocery store. 杂货店中每件商品一行。 The list has 3 columns one containing the item name and the other 2 containing other important data. 该列表有3列,一列包含项目名称,另外两列包含其他重要数据。 The columns are sortable, and to handle the sorting I sort the data array as I need to and call [tableView reloadData] after I'm done sorting the array. 这些列是可排序的,为了处理排序,我根据需要对数据数组进行排序,并在完成数组排序后调用[tableView reloadData] This works fine except there is a long delay of at least a few seconds after reloading the data where the main thread is locked up doing work. 这样可以正常工作,除非在重新加载主线程锁定工作的数据后至少有几秒钟的延迟。 I'm no stranger to list performance as I've had to make smooth lists numerous times in Android. 我对列出性能并不陌生,因为我必须在Android中多次制作流畅的列表。 So from what I can tell I'm not really doing much to cause this. 所以我可以告诉我,实际上并没有做太多事情。 The only thing I can think of is just the large number of items in my array. 我唯一能想到的就是我的数组中的大量项目。 Here is the relevant code: 这是相关代码:

Here are the table methods I am overriding: 以下是我重写的表格方法:

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     return [self.data count];
 }

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"CustomCell";
ReplenishListCell *cell = [self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

if (cell == nil) {
    cell = [[ReplenishListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}

NSMutableDictionary *dictData = [self.data objectAtIndex:indexPath.row];

cell.nameLabel.text = dictData[@"item-description"];
cell.firstLicationColumnLabel.text = dictData[@"store-count"];
cell.secondLicationColumnLabel.text = dictData[@"other-count"];

return cell;
}

-(void)tableView:(UITableView *)replenishTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self showActivityIndicator];

ReplenishListCell *cell = (ReplenishListCell*) [replenishTableView cellForRowAtIndexPath:indexPath];
NSString *nameClicked = cell.nameLabel.text;

[database getItemByName:nameClicked :self];
}

Here is the method I use to sort the array: 这是我用来对数组进行排序的方法:

-(void) sortArray:(NSString *) dictionaryKey {
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:dictionaryKey ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
NSArray *sortedArray = [data sortedArrayUsingDescriptors:sortDescriptors];

[data removeAllObjects];
[data addObjectsFromArray:sortedArray];

[self.tableView reloadData];
}

I do not have any performance issues until after calling [self.tableView reloadData] . 在调用[self.tableView reloadData]之后,我没有任何性能问题。 So I'm wondering if there is something I'm missing, or is there maybe a better way of reloading the data besides reloadData ? 所以我想知道是否有一些我缺少的东西,或者除了reloadData之外还有更好的方法来重新加载数据? Any help will be greatly appreciated. 任何帮助将不胜感激。 I've spent a few hours now debugging and Googling and I haven't come up with a solution yet. 我现在花了几个小时调试和谷歌搜索,我还没有提出解决方案。

One possible cause of your UI hanging is that you're removing and adding all 37.5k objects between two arrays. UI悬挂的一个可能原因是您正在删除并添加两个阵列之间的所有37.5k对象。

Try changing this: 尝试改变这个:

[data removeAllObjects];  
[data addObjectsFromArray:sortedArray];

to this: 对此:

data = sortedArray;

For a large operation you should use a background queue, rather performing that on main queue and blocking UI. 对于大型操作,您应该使用后台队列,而不是在主队列上执行该操作并阻止UI。 You could call reloadData on the main queue after data becomes available from the background operation: 在后台操作中可以获得数据后,您可以在主队列上调用reloadData:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            [self sortArray:<# your key #>];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.tableView reloadData];
    });
});

Also consider using Paul's suggestion, as from the previous answer. 同样考虑使用保罗的建议,如前面的答案。

Your code looks good. 你的代码看起来不错。 Like @paulrehkugler says in his answer, you can just do data = sortedArray where you sort the array. 就像@paulrehkugler在他的回答中所说,你可以在data = sortedArray中对数组进行排序。

With the amount of data you have, consider pre-sorting your data in a background thread. 根据您拥有的数据量,请考虑在后台线程中对数据进行预排序 By my calculations, with 37,500 objects it would take 150K of memory if you keep around 3 arrays with different sort orders. 根据我的计算,如果你保留3个不同排序顺序的数组,那么37,500个对象需要150K的内存。 So when the user chooses to sort by a particular column, you'd already have the data sorted, and you'd just swap the array that is used as the data source. 因此,当用户选择按特定列排序时,您已经对数据进行了排序,并且您只需交换用作数据源的数组。 For the user, sorting then would appear practically instantaneous. 对于用户来说,那么分类几乎是瞬间出现的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM