steharro
steharro

Reputation: 1079

Improve Load Time of Sectioned UITableView

I am displaying a UITableView modally, but it takes about two seconds for it to appear, below is the code that is holding up the transition.

ModalViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // get all songs from iTunes library
    MPMediaQuery *songQuery = [MPMediaQuery songsQuery];
    // put the songs into an array 
    self.songsArray = [songQuery items];
    // create a sectioned array where songs are sectioned by title
    self.sectionedSongsArray = [self partitionObjects:self.songsArray collationStringSelector:@selector(title)];
}

- (NSArray *)partitionObjects:(NSArray *)array collationStringSelector:(SEL)selector
{
    UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation];
    NSInteger sectionCount = [[collation sectionTitles] count];
    NSMutableArray *unsortedSections = [NSMutableArray arrayWithCapacity:sectionCount];
    for(int i = 0; i < sectionCount; i++)
    {
        [unsortedSections addObject:[NSMutableArray array]];
    }
    for (id object in array)
    {
        NSInteger index = [collation sectionForObject:object collationStringSelector:selector];
        [[unsortedSections objectAtIndex:index] addObject:object];
    }
    NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
    for (NSMutableArray *section in unsortedSections)
    {
        [sections addObject:[collation sortedArrayFromArray:section collationStringSelector:selector]];
    }
    return sections;
}

The above code works fine, but its slow to load the modal view first time, is there a better way to do this? Thanks.

Upvotes: 0

Views: 1100

Answers (1)

Noah Witherspoon
Noah Witherspoon

Reputation: 57149

Yeah: don’t do it in -viewDidLoad. A better place would be in the view controller’s -init or -initWithNibNamed:bundle: or whatever, and in the background. Example:

- (id)init
{
    self = [super init];
    if(self)
    {
        // ...

        dispatch_async(dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAULT, 0), ^{
            // since it's not on the main thread, you need to create your own autorelease pool to prevent leaks
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

            MPMediaQuery *songQuery = [MPMediaQuery songsQuery];
            self.songsArray = [songQuery items];            
            self.sectionedSongsArray = [self partitionObjects:self.songsArray collationStringSelector:@selector(title)];

            // UI calls have to be on the main thread, so we go back to that here
            dispatch_async(dispatch_get_main_queue(), ^{
                if([self isViewLoaded])
                {
                    [self.tableView reloadData];
                }
            });

            // this releases any objects that got autoreleased earlier in the block
            [pool release];
        });
    }

    return self;
}

Your -tableView:numberOfRowsInSection: method should of course now check whether sectionedSongsArray is non-nil and in that case return 0 (or 1 if you want to display a “loading” cell, which you probably should).

Upvotes: 1

Related Questions