Как предотвратить сбой при выборе определенного контакта с помощью AdressBookUI

Я получаю крах на этой линии.

    phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(numbers, index));

Если выбран первый номер телефона, я получаю индекс 1, что неверно. Это должно быть 0 и, следовательно, выбирает неправильный номер. Если я выберу второе число, это даст индекс -1, который завершит работу приложения.

#pragma mark helper methods

- (void)didSelectPerson:(ABRecordRef)person identifier:(ABMultiValueIdentifier)identifier {
    NSString *phoneNumber = @"";
    ABMultiValueRef numbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
    if (numbers) {
        if (ABMultiValueGetCount(numbers) > 0) {
            CFIndex index = 0;
            if (identifier != kABMultiValueInvalidIdentifier) {
                index = ABMultiValueGetIndexForIdentifier(numbers, identifier);
            }
            phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(numbers, index));
        }
        CFRelease(numbers);
    }
    self.numberTextField.text = [NSString stringWithFormat:@"%@", phoneNumber];
}

1 ответ

Решение

В iOS 8.3 (и, вероятно, в предыдущей версии iOS 8) есть ошибка при работе с копиями контактов, у которых удалены номера телефонов / электронные письма. Документация для ABPeoplePickerNavigationController говорится, что:

В iOS 8 и более поздних версиях для запуска контроллера навигации средства выбора людей не требуется, чтобы приложение имело доступ к контактам пользователя, и пользователю не будет предложено предоставить доступ. Если само приложение не имеет доступа к контактам пользователя, временная копия контакта, выбранного пользователем, будет возвращена приложению.

В моем тестировании у меня был контакт с тремя телефонными номерами (давайте позвоним им 111, 222 а также 333). Похоже, что identifiers являются фиксированными, стабильными нулевыми значениями. Таким образом, мои три номера телефонов были идентификатором 0 в 2, Если номер телефона удален, идентификаторы не меняются. Ноль на основе indexОни используются для доступа к текущему списку телефонных номеров (или электронных писем и т. д.) и ABMultiValueGetIndexForIdentifier используется для преобразования идентификатора в индекс.

В моем тесте я удалил первый номер телефона, 111, Это не меняет идентификаторы для оставшихся телефонных номеров (222=1, 333=2).

Когда я использовал ABPeoplePickerNavigationController и выбрал первый номер телефона (222) метод делегата peoplePickerNavigationController: didSelectPerson:property:identifier: правильно передал идентификатор 1, Тем не мение, ABMultiValueGetIndexForIdentifier вернул индекс 1, а не 0, и мое приложение скопировало номер телефона 333 как он думал, что пользователь выбрал. Если пользователь выбрал 333 тогда мне правильно передали идентификатор 2 но ABMultiValueGetIndexForIdentifier преобразовал это в -1 а затем незащищенный вызов ABMultiValueCopyValueAtIndex разбился.

Таким образом, при работе с копией контакта (что происходит в iOS 8, когда приложение не авторизовано для доступа к адресной книге), iOS, похоже, использует идентификаторы, основанные на реальном контакте, но индексы основаны на копия. Кажется, что копия забыла ранее удаленный номер телефона, и сопоставление идентификатора и индекса происходит неправильно, если пользователь выбирает номер телефона, который был создан после ранее удаленного номера телефона. Это работает, если пользователь не удалил номера телефонов или если они удалили номера телефонов после того, который они выбрали.

Обходной путь - усложнить приложение, заставив его запросить у пользователя разрешение на доступ к адресной книге, используя ABAddressBookRequestAccessWithCompletion, После предоставления приложению не будет предоставлена копия выбранного контакта, и сопоставление идентификатора и индекса будет работать правильно.

Другие вопросы по тегам