peten
peten

Reputation: 113

Performance issue creating Section Index Titles for UITableView

I'm displaying an array of contacts ( [[ContactStore sharedStore]allContacts] ) in a tableview and have divided the list into alphabetic sections. I have used the following code to return an array of the first letters of the contacts, and a dictionary of the number of entries per letter.

    //create an array of the first letters of the names in the sharedStore
nameIndex = [[NSMutableArray alloc] init];

//create a dictionary to save the number of names for each first letter
nameIndexCount = [[NSMutableDictionary alloc]init];

for (int i=0; i<[[[ContactStore sharedStore]allContacts]count]; i++){

//Get the first letter and the name of each person
    Contact *p = [[[ContactStore sharedStore]allContacts]objectAtIndex:i];
    NSString *lastName = [p lastName];
    NSString *alphabet = [lastName substringToIndex:1];


    //If that letter is absent from the dictionary then add it and set its value as 1 
    if ([nameIndexCount objectForKey:alphabet] == nil) {
        [nameIndex addObject:alphabet];
        [nameIndexCount setValue:@"1" forKey:alphabet];
    //If its already present add one to its value
    } else {

        NSString *newValue = [NSString stringWithFormat:@"%d", ([[nameIndexCount valueForKey:alphabet] intValue] + 1)];

        [nameIndexCount setValue:newValue forKey:alphabet];
    }
} 

This works, however it is very slow when the array is large, I'm sure there's a better way to do this but I'm quite new to this so am not sure how. Are there any suggestions for a better way to do this?

Upvotes: 0

Views: 635

Answers (2)

eric.mitchell
eric.mitchell

Reputation: 8855

Although Bio Cho has a good point, you might see an increase in performance by calling

[[ContactStore sharedStore]allContacts]

only once. For example:

nameIndex = [[NSMutableArray alloc] init];
nameIndexCount = [[NSMutableDictionary alloc] init];

/*
 Create our own copy of the contacts only once and reuse it
 */
NSArray* allContacts = [[ContactStore sharedStore] allContacts];

for (int i=0; i<[allContacts count]; i++){
    //Get the first letter and the name of each person
    Contact *p = allContacts[i];
    NSString *lastName = [p lastName];
    NSString *alphabet = [lastName substringToIndex:1];

    //If that letter is absent from the dictionary then add it and set its value as 1 
    if ([nameIndexCount objectForKey:alphabet] == nil) {
        [nameIndex addObject:alphabet];
        [nameIndexCount setValue:@"1" forKey:alphabet];
    //If its already present add one to its value
    } else {
        NSString *newValue = [NSString stringWithFormat:@"%d", ([[nameIndexCount 
            valueForKey:alphabet] intValue] + 1)];

        [nameIndexCount setValue:newValue forKey:alphabet];
    }
} 

Though I can't say for sure, I'd guess that repeatedly accessing your shared store is what's killing you. Maybe only accessing it once will give you what you need.

Upvotes: 2

Bio
Bio

Reputation: 505

Consider storing your contacts in Core Data and using an NSFetchedResultsController.

The NSFetchedResultsController will only load a subset of the rows which are visible on the table view, thus preventing your user from having to wait for all the contacts to be sorted.

NSFetchedResultsController will also sort your contacts by an attribute (ie. first or last name), and you can set your section titles to be the first letter of the field you're sorting by.

Take a look at this question and this tutorial.

Upvotes: 0

Related Questions