ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C Часть 1

Адресная книга

Наверняка каждый из вас знает, что такое адресная книга и с чем её едят. В адресной книге вы храните ваших близких и знакомых людей, их контакты, адреса, дни рождения. Каждый человек имеет такие свойства как имя, фамилия, номер телефона или адрес электронной почты. AddressBook.framework в iOS SDK позволяет нам взаимодействовать с базой данных адресной книги на устройстве. Для этого добавте вышеупомянутый фреймворк в проект. После чего, мы без особых проблем можем получить массив всех лиц в адресной книге пользователя, вставлять и изменять различные значения и многое другое.

Первым делом давайте выведем в консоль все записи из адресной книги. Для работы с ней мы должны воспользоваться функциейABAddressBookCreate() и после успешной проверки её на наличие записей начинаем работу. Если вы компилируете приложение на симуляторе и хотите благополучно дойти до этого шага – добавьте в адресную книгу симулятора пару записей. Далее, воспользовавшись функцией ABAddressBookCopyArrayOfAllPeople() мы копируем в переменную allPeople все записи из адресной книги. После чего, если конечно же он не пуст, в переменную  thisPerson мы по очереди помещаем данные каждой записи из адресной книги с помощью функции CFArrayGetValueAtIndex(), при помощи ABRecordCopyValue() копируем в вспомогательные строковые переменные подробную информацию в виде имени, фамилии и адреса электронной почты (эти свойства взяты исключительно для примера) и выводим их в консоль. Ну и конечно не забываем очищать память функцией CFRelease(). Всё просто:
<code data-result="[object Object]">- (IBAction)showContacts {
    ABAddressBookRef addressBook = ABAddressBookCreate();
    if (addressBook) {
        CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
        if (allPeople) {
            for (int index=0; index&lt;CFArrayGetCount(allPeople); index++){
                ABRecordRef thisPerson = CFArrayGetValueAtIndex(allPeople, index);

                NSString *firstName = (__bridge NSString *)ABRecordCopyValue(thisPerson, 
                                                                             kABPersonFirstNameProperty);
                NSString *lastName = (__bridge NSString *)ABRecordCopyValue(thisPerson, 
                                                                            kABPersonLastNameProperty);

                ABMultiValueRef emailMultiValue = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
                NSArray *emailAddresses = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(emailMultiValue);

                NSLog(@"First Name = %@", firstName);
                NSLog(@"Last Name = %@", lastName);
                NSLog(@"Address = %@", emailAddresses);

                CFRelease(emailMultiValue);
            }
            CFRelease(allPeople);
        }
        CFRelease(addressBook);
    }
}</code>
Далее я покажу несколько методов редактирования адресной книги, но после каждых вносимых нами изменений ее следует сохранять. Дабы не дублировать код, я предлагаю создать отдельный метод для этой цели:
<code data-result="[object Object]">- (void)saveAddressBook:(ABAddressBookRef)addressBook {
    if (ABAddressBookHasUnsavedChanges(addressBook)) {
        CFErrorRef error = nil;
        if (ABAddressBookSave(addressBook, &amp;error)){
            NSLog(@"Адресная книга сохранена");
        } else {
            NSLog(@"Не удалось сохранить адресную книгу");
        }
    }
}</code>
Поскольку процесс сохранения адрессной книги достаточно «тяжелый» для устройства — следует убедиться, внесены ли изменения в эту самую книгу. И сохранять только в том случае, если в ней есть несохраненные данные. Именно так и работает наш метод saveAddressBook.
Теперь добавим запись в адресную книгу. Для этого нам понадобится функция ABRecordSetValue() С помощью нее мы сможем добавить всевозможные данные в запись (обратите внимание на тот факт, если вы добавляете свойство, которое может принимать не единсвенное значение, то необходимо воспользоваться функцией ABMultiValueAddValueAndLabel()), а потом саму запись добавляем в адресную книгу при помощи ABAddressBookAddRecord(). Запись в адресную книгу добавлена, однако вы её там не увидите, пока не вызовете функцию ABAddressBookSave(). Вызвав её — вы добьётесь необходимого результата.
<code data-result="[object Object]">- (IBAction)addPerson {
    ABAddressBookRef addressBook = ABAddressBookCreate();
    if (addressBook) {
        NSString *firstName = @"Peter";
        NSString *lastName = @"Vasilievich";
        NSString *phone = @"0931969695";

        ABRecordRef person = ABPersonCreate();
        if (!person) {
            NSLog(@"Не удалось создать новую запись");
            return;
        }

        CFErrorRef error = nil;

        BOOL couldSetFirstName = ABRecordSetValue(person, 
                                                  kABPersonFirstNameProperty, 
                                                  (__bridge CFStringRef)firstName, 
                                                  &amp;error);
        BOOL couldSetLastName = ABRecordSetValue(person, 
                                                 kABPersonLastNameProperty, 
                                                 (__bridge CFStringRef)lastName, 
                                                 &amp;error);

        ABMutableMultiValueRef phones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
        ABMultiValueAddValueAndLabel(phones, 
                                     (__bridge CFStringRef)phone, 
                                     kABPersonPhoneMobileLabel,
                                     NULL);
        BOOL couldSetPhoneNumber = ABRecordSetValue(person, 
                                                    kABPersonPhoneProperty, 
                                                    phones, 
                                                    &amp;error);
        CFRelease(phones);

        if (couldSetFirstName &amp;&amp; couldSetLastName &amp;&amp; couldSetPhoneNumber) {
            NSLog(@"Удалось установить все данные");
        }

        if (ABAddressBookAddRecord(addressBook, person, &amp;error)) {
            NSLog(@"Запись добавлена в адресную книгу");
        } 

        [self saveAddressBook:addressBook];
        CFRelease(addressBook);
    }
}</code>
Любой контакт из адресной книги можно добавлять в группы. Но сначала нам нужно создать эту самую группу. Кроме всего уже знакомого здесь присутствует функция ABGroupCreate() и ABAddressBookCopyArrayOfAllGroups(), а в остальном практически без изменений как и при добавлении контакта. После добавления этих методов в консоль должна вывестись инфа, что группа iMaladec успешно добавлена, либо, что она уже существует.
<code data-result="[object Object]">- (IBAction)createGroup {
    NSString *newGroupName = @"iMaladec";

    ABAddressBookRef addressBook = ABAddressBookCreate();
    if (addressBook){

        BOOL groupNameIsEqual = NO;

        CFArrayRef allGroups = ABAddressBookCopyArrayOfAllGroups(addressBook);
        if (allGroups){
            for (int index=0; index&lt;CFArrayGetCount(allGroups); index++){
                ABRecordRef group = CFArrayGetValueAtIndex(allGroups, index);
                NSString *groupName = (__bridge NSString *)ABRecordCopyValue(group, 
                                                                             kABGroupNameProperty);

                if ([groupName isEqualToString:newGroupName]) {
                    groupNameIsEqual = YES;
                    break;
                }
            }
        }
        CFRelease(allGroups);

        if (groupNameIsEqual) {
            NSLog(@"Такая группа уже существует");
        } else {
            ABRecordRef group = ABGroupCreate();
            if (!group){
                NSLog(@"Ошибка при создании группы");
                return;
            }

            CFErrorRef error = nil;
            BOOL couldSetGroupName = ABRecordSetValue(group, 
                                                      kABGroupNameProperty, 
                                                      (__bridge CFStringRef)newGroupName, 
                                                      &amp;error);
            if (couldSetGroupName){
                if (ABAddressBookAddRecord(addressBook, group, &amp;error)){
                    NSLog(@"Новая группа добавлена");
                    [self saveAddressBook:addressBook];
                } else {
                    NSLog(@"Не удалось добавить новую группу"); 
                }
            } else {
                NSLog(@"Ошибка при установке имени группе"); 
            }

        }

        CFRelease(addressBook);
    }
}</code>
Теперь изменим метод создания контакта таким образом, чтобы он попадал в созданную группу:
<code data-result="[object Object]">- (IBAction)addPerson {
    ABAddressBookRef addressBook = ABAddressBookCreate();
    if (addressBook) {
        NSString *firstName = @"Peter";
        NSString *lastName = @"Vasilievich";
        NSString *phone = @"0931969695";

        ABRecordRef person = ABPersonCreate();
        if (!person) {
            NSLog(@"Не удалось создать новую запись");
            return;
        }

        CFErrorRef error = nil;

        BOOL couldSetFirstName = ABRecordSetValue(person, 
                                                  kABPersonFirstNameProperty, 
                                                  (__bridge CFStringRef)firstName, 
                                                  &amp;error);
        BOOL couldSetLastName = ABRecordSetValue(person, 
                                                 kABPersonLastNameProperty, 
                                                 (__bridge CFStringRef)lastName, 
                                                 &amp;error);

        ABMutableMultiValueRef phones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
        ABMultiValueAddValueAndLabel(phones, 
                                     (__bridge CFStringRef)phone, 
                                     kABPersonPhoneMobileLabel,
                                     NULL);
        BOOL couldSetPhoneNumber = ABRecordSetValue(person, 
                                                    kABPersonPhoneProperty, 
                                                    phones, 
                                                    &amp;error);
        CFRelease(phones);

        if (couldSetFirstName &amp;&amp; couldSetLastName &amp;&amp; couldSetPhoneNumber) {
            NSLog(@"Удалось установить все данные");
        }

        //Добавление фото
        UIImage *photo = [UIImage imageNamed:@"logo.png"];
        NSData *photoData = UIImagePNGRepresentation(photo);
        if (ABPersonSetImageData(person, (__bridge CFDataRef)photoData, &amp;error)) {
            NSLog(@"Фото добавлено");
        }
        //Добавление фото

        if (ABAddressBookAddRecord(addressBook, person, &amp;error)) {
            NSLog(@"Запись добавлена в адресную книгу");
        } 

        [self saveAddressBook:addressBook];

        //Добавление в группу
        CFArrayRef allGroups = ABAddressBookCopyArrayOfAllGroups(addressBook);
        if (allGroups){
            for (int index=0; index&lt;CFArrayGetCount(allGroups); index++){
                ABRecordRef group = CFArrayGetValueAtIndex(allGroups, index);
                NSString *groupName = (__bridge NSString *) ABRecordCopyValue(group, kABGroupNameProperty);

                if ([groupName isEqualToString:@"iMaladec"]) {
                    if (ABGroupAddMember(group, person, &amp;error)) {
                        NSLog(@"Контакт добавлен в группу");
                    } else {
                        NSLog(@"Не получилось добавить контакт в группу");
                    }
                    break;
                }
            }
        }
        CFRelease(allGroups);
        [self saveAddressBook:addressBook];
        //Добавление в группу

        CFRelease(addressBook);
    }
}</code>
Здесь следует обратить внимание на важный момент. Группу можно установить только уже созданному контакту. Поэтому код, отвечающий за установку группы я поместил после того как контакт создался и сохранилась адресная книга. Кроме установки группы я добавил код, который устанавливает фотографию контакта. Чтобы все работало правильно — вам следует скачать файлик по ссылки и добавить его в проект.
Для удаления контакта с адресной книги нам понадобиться метод ABAddressBookRemoveRecord(). Но перед этим следует найти этот самый контакт:
<code data-result="[object Object]">- (IBAction)removePerson {
    ABAddressBookRef addressBook = ABAddressBookCreate();
    if (addressBook) {
        CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
        if (allPeople) {
            for (int index=0; index&lt;CFArrayGetCount(allPeople); index++){
                ABRecordRef thisPerson = CFArrayGetValueAtIndex(allPeople, index);
                NSString *firstName = (__bridge NSString *)ABRecordCopyValue(thisPerson, 
                                                                             kABPersonFirstNameProperty);

                if ([firstName isEqualToString:@"Peter"]) {
                    CFErrorRef error = nil;
                    if (ABAddressBookRemoveRecord(addressBook, thisPerson, &amp;error)) {
                        NSLog(@"Запись удалена");
                    }
                }
            }
            CFRelease(allPeople);
        }

        [self saveAddressBook:addressBook];
        CFRelease(addressBook);
    }
}</code>
В данном уроке приведены примеры далеко не всех возможностей адресной книги, однако этих минимальных знаний хватит вам справиться с любой задачей, будь то добавление дня рождения или номера скайпа.
В шестой версии прошивки Apple добавила ограничение на доступ к адресной книгой. Поэтому прежде чем проводить с ней какие либо манипуляции — следует запросить разрешение у пользователя (в противном случае приложение будет просто падать). Делается это с помощью не хитрого метода:
<code data-result="[object Object]">- (BOOL)accessGranted {
    ABAddressBookRef addressBook = ABAddressBookCreate();
    __block BOOL accessGranted = NO;
    if (ABAddressBookRequestAccessWithCompletion != NULL) {
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);

        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            accessGranted = granted;
            dispatch_semaphore_signal(sema);
        });

        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        dispatch_release(sema);
    } else {
        accessGranted = YES;
    }

    CFRelease(addressBook);

    return accessGranted;
}</code>
Этот код следует вызывать каждый раз при начале работы с адресной книгой. То есть, метод получения списка контактов должен выглядеть так:
<code data-result="[object Object]">- (IBAction)showContacts {
    if (!self.accessGranted) {
        NSLog(@"Доступ к адресной книге закрыт");
        return;
    }

    //Код получения списка
}</code>
Если приложение запускалось впервые на устройстве — пользователь увидит следующее сообщение:
Выполнение функции accessGranted прерывается до завершения выбора пользователя. Так, что если владелец телефона не захочет давать доступ к своим контактам — вам ничего не останется как завершить работу метода обращенного к адресной книге.

Comments are closed.