Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 3983904
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 20, 20262026-05-20T05:42:18+00:00 2026-05-20T05:42:18+00:00

My iPad app features a UITableView populated from a feed. Like most RSS readers,

  • 0

My iPad app features a UITableView populated from a feed. Like most RSS readers, it displays a list of links to blog posts in reverse chronological order, with their titles and a summary of each post. The feed updates frequently, and is quite large, around 500 posts. I’m using libxml2 push parsing to efficiently download and parse the feed in an NSOperation subclass, constructing entry objects and updating a database as I go. But then I need to update the UITableView with changes.

So far, the app has been updating the UITableView for every post parsed, as it is parsed. The parser performs a selector on the main thread to do this work. But this leads to some serious lag for a couple of seconds if a lot of cells need to be updated. I can mitigate this by running the table update on a background thread, but it seems that this is not a good idea. So now I’m trying to figure out how to update the table more efficiently on the main thread.

I could just call reloadData when all the posts have been parsed, but it’s not very user friendly: there’s no animation to indicate that anything has changed, just a flash and the new data is there. I’d much rather have it animate to show that new posts are added and old posts removed. Existing posts that are not removed from the feed should be pushed down the table by the new posts appearing at the top.

I know this is possible. Byline, to give one example, does a beautiful job. Each post is added or removed from the UITableView one-at-a-time with no gaps showing the table background. All without making the UI in the least bit unresponsive. How is that done??

My latest attempt is to update the table only after all the posts have been parsed (the parser is quite fast, so it’s not much of a delay). It then loads the existing posts in an NSDictionary mapping their IDs to their indexes in the array used as the table data source. It then iterates over every object in the newly-parsed array of posts, adding NSIndexPath for each to arrays that are later passed to -insertRowsAtIndexPaths:withRowAnimation:, -deleteRowsAtIndexPaths:withRowAnimation:, and -reloadRowsAtIndexPaths:withRowAnimation: as appropriate to insert, remove, move, or update cells. For 500 posts, this takes around 4 seconds to update, with the UI completely unresponsive. That time is used almost exclusively for the UITableView animated updates; iterating over the two arrays of posts takes very little time.

I then modified it so that those are updated without animation, and I have separate arrays to insert/delete/reload with animation only for row positions corresponding to currently-visible rows. This is better, but gaps appear as posts are removed and new ones added.

Sorry this is so long-winded, but here’s the upshot:

How can I update a UITableView, with new cells pushed on, others pushed off, and still others moved from one position to another, with up to 500 cells in the UITableView (6-8 are visible at one time), and each animation happening in sequence, all while the UI remains completely responsive?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-20T05:42:19+00:00Added an answer on May 20, 2026 at 5:42 am

    This question actually has three answers. That is, there are three parts to this question:

    1. How to keep the UI responsive
    2. How to keep the updating fast
    3. How to make table update animation smooth

    UI Responsiveness

    To solve the first problem, I now make sure that no more than one table-updating message can be delivered on each iteration of the main event loop. That prevents the main thread from locking up if the background thread is feeding it stuff to do faster than it can cope with it.

    This is done thanks to example code sent to me by Byline author Milo Bird, which I then integrated into Dave Dribin‘s DDInvocationGrabber. This interface makes it super easy to queue a method to be invoked on the next available iteration of the main event loop:

    [[(id)delegate queueOnMainThread]
        parserParsedEntries:parsedEntries
                   inPortal:parsedPortal];
    

    I quite like how easy it is to use this method. The parser now uses it to call all of the delegate methods, most of which update the UI. I’ve released this code on GitHub.

    Performance

    As for performance, I was originally updating one UITableView row at a time. This was effective, but somewhat inefficient. I went back and studied the XMLPerformance example, where I noticed that the parser was waiting until it had collected 10 items before dispatching to the main thread to update the table. This was key to keeping the performance up without making the UI lock up by updating all 500 rows at once. I played around with updating 1, 10, and all 500 rows in a single call, and updating 10 seemed to offer the best tradeoff between performance and UI lockup. five would probably work pretty well, too.

    Animation

    And finally, there’s the animation. Watching the “Mastering Table Views” WWDC 2010 session, I realized that my use of the deleteRowsAtIndexPaths:withRowAnimation: and updateRowsAtIndexPaths:withRowAnimation: methods was wrong. I had been keeping track of where things should be added and removed in the table and adjusting the indexes as appropriate, but it turns out that’s not necessary. Inside a table update block, one only needs to reference the index of a row from before the update, regardless of how many may be inserted or deleted to change its position. The update block, apparently, does all that bookkeeping for you. (Go to about the 8:45 mark in the video for the key example).

    Thus, the delegate method that updates the table for the number of entries passed to it by the parser (currently 10-at-a-time) now explicitly tracks the positions of rows to be updated or deleted from before the update block, like so:

    NSMutableDictionary *oldIndexFor = [NSMutableDictionary dictionaryWithCapacity:posts.count];
    int i = 0;
    for (PostModel *e in  posts) {
        [oldIndexFor setObject:[NSNumber numberWithInt:i++] forKey:e.ident];
    }
    
    NSMutableArray *insertPaths = [NSMutableArray array];
    NSMutableArray *deletePaths = [NSMutableArray array];
    NSMutableArray *reloadPaths = [NSMutableArray array];
    BOOL modified = NO;
    
    for (PostModel *entry in entries) {
        NSNumber *num = [oldIndexFor objectForKey:entry.ident];
        NSIndexPath *path = [NSIndexPath indexPathForRow:currentPostIndex inSection:0];
        if (num == nil) {
            modified = YES;
            [insertPaths addObject:path];
            [posts insertObject:entry atIndex:currentPostIndex];
        } else {
            // Find its current position in the array.
            NSUInteger foundAt = [posts indexOfObject:entry];
            if (foundAt == currentPostIndex) {
                // Reload it if it has changed.
                if (entry.savedState != PostModelSavedStateUnmodified) {
                    modified = YES;
                    [posts replaceObjectAtIndex:foundAt withObject:entry];
                    [reloadPaths addObject:[NSIndexPath indexPathForRow:num.intValue inSection:0]];
                }
            } else {
                // Move it.
                modified = YES;
                [posts removeObjectAtIndex:foundAt];
                [posts insertObject:entry atIndex:currentPostIndex];
                [insertPaths addObject:path];
                [deletePaths addObject:[NSIndexPath indexPathForRow:num.intValue inSection:0]];
            }
        }
        currentPostIndex++;
    }
    if (modified) {
        [tableView beginUpdates];
        [tableView insertRowsAtIndexPaths:insertPaths withRowAnimation:UITableViewRowAnimationTop];
        [tableView deleteRowsAtIndexPaths:deletePaths withRowAnimation:UITableViewRowAnimationBottom];
        [tableView reloadRowsAtIndexPaths:reloadPaths withRowAnimation:UITableViewRowAnimationFade];
        [tableView endUpdates];
    }
    

    Comments welcome. It’s entirely possible that there are more efficient ways to do this (the use of -[NSArray indexOfObject:] is particularly suspicious to me), and that I may have missed some other subtlety.

    But even so, this is a huge improvement for my app. The UI now stays (mostly) responsive during a sync, the sync is fast, and the table update animation looks just about right.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I've made a universal iPhone/iPad app (transitioned from iPhone only), but in a future
I was wondering if it was possible to launch an iPad app directly from
I have an iPhone app and would like to create iPad version of it.
My iPad app hangs on startup sometimes. It looks like the main thread is
My iPad app displays a movie full screen using the convenient MPMoviePlayerViewController class. I
I have an iPad app that is set to start in landscape mode. From
I have a graphic-intensive iPad app that features a UIWebView. Using the simulator (iOS
The music app on the iPad has quite a lot of interesting custom UI
I want to develop a native universal app(i.e for iPhone and iPad) for my
The advice from Apple is to always set the Base SDK for iPhone/iPad projects

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.