UITableView reloadData taking too much time

2020-07-25 23:43发布

问题:

I'm using TBXML+HTTP to get XML data from a website. What I want to do is populate a UITableView with the processed data. I've created a NSMutableArray that holds all the entries and, as far as that goes, everything is working fine. The problem is when, after successfully fetching the data from the server and storing it in the array, I try to update the table to show the data, using reloadData.

It takes about 5 seconds to populate the table with 20 rows. The weird part is that the fetching is happening really fast, so the data is available right away. I do not understand what is taking so long. Here is some info from the log:

2012-03-17 18:46:01.045 MakeMyApp[4571:207] numberOfSectionsInTableView: 1
2012-03-17 18:46:01.047 MakeMyApp[4571:207] numberOfRowsInSection: 0
2012-03-17 18:46:01.244 MakeMyApp[4571:1f03] numberOfSectionsInTableView: 1
2012-03-17 18:46:01.245 MakeMyApp[4571:1f03] numberOfRowsInSection: 20
2012-03-17 18:46:01.245 MakeMyApp[4571:1f03] Ok, I'm done. 20 objects in the array.
2012-03-17 18:46:01.246 MakeMyApp[4571:1f03] Finished XML processing.
2012-03-17 18:46:06.197 MakeMyApp[4571:1f03] cellForRowAtIndexPath:

As you can see, it fires the pair numberOfSectionsInTableView:/numberOfRowsInSection: two times: the first is when the view loads, the second is when I do [self.tableView reloadData];

You see that, in less than a second, the array is populated with the 20 objects and all the work processing the XML is done. How is cellForRowAtIndexPath: fired only 5 seconds later?

Here are some parts of the code that might help finding the problem:

- (void)createRequestFromXMLElement:(TBXMLElement *)element {
    // Let's extract all the information of the request
    int requestId = [[TBXML valueOfAttributeNamed:@"i" forElement:element] intValue];

    TBXMLElement *descriptionElement = [TBXML childElementNamed:@"d" parentElement:element];
    NSString *description = [TBXML textForElement:descriptionElement];

    TBXMLElement *statusElement = [TBXML childElementNamed:@"s" parentElement:element];
    int status = [[TBXML textForElement:statusElement] intValue];

    TBXMLElement *votesCountElement = [TBXML childElementNamed:@"v" parentElement:element];
    int votesCount = [[TBXML textForElement:votesCountElement] intValue];    

    // Creating the Request custom object
    Request *request = [[Request alloc] init];

    request.requestId = requestId;
    request.description = description;
    request.status = status;
    request.votes_count = votesCount;

    [requestsArray addObject:request];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    appListCell *cell = (appListCell *)[tableView dequeueReusableCellWithIdentifier:@"appListCell"];

    Request *request = [requestsArray objectAtIndex:indexPath.row];

    cell.appIdLabel.text = [NSString stringWithFormat:@"#%d", request.requestId];
    cell.appTextLabel.text = request.description;
    cell.appVotesLabel.text = [NSString stringWithFormat:@"%d votes", request.votes_count];

    return cell;
}

Thanks a lot!

EDIT:

- (void)traverseXMLAppRequests:(TBXMLElement *)element {
    int requestCount = 0;
    TBXMLElement *requestElement = element->firstChild;

    // Do we have elements inside <re>?
    if ((requestElement = (element->firstChild))) {
        while (requestElement) {
            [self createRequestFromXMLElement:requestElement];

            requestCount++;

            requestElement = [TBXML nextSiblingNamed:@"r" searchFromElement:requestElement];
        }
    }

    [self.tableView reloadData];   

    NSLog(@"Ok, I'm done. %d objects in the array.", [requestsArray count]);

}

EDIT 2: I've tried fetching the information of just 1 row, instead of 20, and the delay is exactly the same.

回答1:

I know this is a really old question, but I've just come across the exact same issue and think I might know the cause. Might help someone who stumbles across this same question...

I suspect that your reloadData call is happening on a background thread as opposed to the main thread. What you describe is the exact effect of this - the code runs but there is a long delay (5-10 secs) in updating the user interface.

Try changing the reloadData call to:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
});


回答2:

You are calling reloadData on a thread other than the mainThread

Make sure to reload your tableView's data on main thread like in the below:

OBJ-C:

[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

Swift 3:

DispatchQueue.main.async {
   self.tableView.reloadData()
}


回答3:

Where does:

- (void)createRequestFromXMLElement:(TBXMLElement *)element

get called? Sound like you might be making 20 web requests to get that file contents. That would definitely make things slow (as opposed to doing one request to get the entire XML file and parsing that locally).

Can you post your whole VC code?