antf
antf

Reputation: 3222

How to read the Address Book as fast as other apps (like Viber, Whatsapp...)

I am writing an app where I need to read the Address Book data to search for some contacts of interest, something similar to what many apps do nowadays (like Viber, Whatsapp, Tango...). I need to do matching so I send the data to a server and reply to the client which contacts have the same app installed on their devices.

I have no problem in the logic or mechanism of the idea, my problem is speed! I was able to do what I want but the process took 27 seconds to finish on iPhone4 with 500 contacts on it. On the same device if we try Viber or Whatsapp (or any similar app) the process takes less than 5 seconds.

My method is very straightforward, I do a for loop and read everything. How can I do the same thing but much faster like other apps?

Here is the code that I use:

    //variable definitions
    ABAddressBookRef addressBook = ABAddressBookCreate();
    CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
    CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(people), people);

    //sort the contents of the Mutable Array
    CFArraySortValues(peopleMutable, CFRangeMake(0, CFArrayGetCount(peopleMutable)), (CFComparatorFunction) ABPersonComparePeopleByName, (void*) ABPersonGetSortOrdering());

    //read the Address Book
    NSString *fullName, *number;
    ABRecordRef record = ABPersonCreate();
    ABMutableMultiValueRef multi;
    int contactID;
    int nameCount=0;//used to count the names in the string to send to server
    NSMutableString *strNamesToSend = [[NSMutableString alloc] init];

    for(CFIndex i=0; i< CFArrayGetCount(people); i++)
    {
        record = CFArrayGetValueAtIndex(people, i);
        multi = ABRecordCopyValue(record, kABPersonPhoneProperty);

        //Contact ID
        contactID = (int)ABRecordGetRecordID(record);

        //Full Name
        fullName = [NSString stringWithFormat:@"%@ %@", (NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty), (NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty)];
        fullName = [fullName stringByReplacingOccurrencesOfString:@" (null)" withString:@""];

        //fill data into AddressBook Table
        if(dbOpen == SQLITE_OK)
        {
            //pure sqlite3 work to save the names in my app
        }

        //Get multiple numbers from each user (if any)
        for(CFIndex j=0; j<ABMultiValueGetCount(multi); j++)
        {
            number = (NSString *)ABMultiValueCopyValueAtIndex(multi, j);

            nameCount++;

            //fill data into AllNumbers Table
            if(dbOpen == SQLITE_OK)
            {
                 //another sqlite3 work to save the numbers
            }
        }

        //send to the server every 29 numbers so we don't send all the 500 numbers at once
        if(nameCount > 29)
        {
            //send to server
        }

Upvotes: 3

Views: 3327

Answers (1)

jnic
jnic

Reputation: 8785

Have you tried profiling your code at all? A profiler should be able to quickly identify the slow parts of your code.

From a very brief inspection, I notice you're counting the array size at each iteration rather than just once. Move it out of your loop:

int count = CFArrayGetCount(people);
for (CFIndex i = 0; i < count; i++)

You don't detail the SQL calls you're making, but the fact you're checking for SQLITE_OK implies that you're opening the database each time through the loop. If this is the case you should move this call outside your loop rather than opening the database each time.

I notice that nameCount isn't being reset, which means that once it reaches 29, your if case will be hit every single time, causing a huge number of network requests.

Upvotes: 5

Related Questions