Reputation: 3222
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
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