Как читать адресную книгу так же быстро, как и другие приложения (например, Viber, Whatsapp ...) - PullRequest
3 голосов
/ 09 января 2012

Я пишу приложение, в котором мне нужно прочитать данные адресной книги, чтобы найти интересующие контакты, что-то похожее на то, что делают многие приложения в настоящее время (например, Viber, Whatsapp, Tango ...). Мне нужно выполнить сопоставление, поэтому я отправляю данные на сервер и отвечаю клиенту, на контактах которого установлено такое же приложение на их устройствах.

У меня нет проблем в логике или механизме идеи, моя проблема в скорости! Я смог сделать то, что хочу, но процесс занял 27 секунд на iPhone4 с 500 контактами на нем. На том же устройстве, если мы попробуем Viber или Whatsapp (или любое подобное приложение), этот процесс займет менее 5 секунд.

Мой метод очень прост, я делаю цикл for и читаю все. Как я могу сделать то же самое, но гораздо быстрее, чем другие приложения?

Вот код, который я использую:

    //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
        }

1 Ответ

5 голосов
/ 09 января 2012

Вы вообще пытались профилировать свой код? Профилировщик должен быть в состоянии быстро идентифицировать медленные части вашего кода.

Из очень короткого осмотра я заметил, что вы подсчитываете размер массива на каждой итерации, а не один раз. Переместите это из своей петли:

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

Вы не детализируете вызовы SQL, которые вы делаете, но факт проверки SQLITE_OK подразумевает, что вы открываете базу данных каждый раз через цикл. В этом случае вы должны перемещать этот вызов за пределы цикла, а не открывать базу данных каждый раз.

Я заметил, что nameCount не сбрасывается, а это означает, что, как только он достигнет 29, ваш случай if будет попадать каждый раз, вызывая огромное количество сетевых запросов.

...