Как предотвратить сбой при выборе определенного контакта с помощью 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
). Похоже, что identifier
s являются фиксированными, стабильными нулевыми значениями. Таким образом, мои три номера телефонов были идентификатором 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
, После предоставления приложению не будет предоставлена копия выбранного контакта, и сопоставление идентификатора и индекса будет работать правильно.