使用 AdressBookUI 选择特定联系人时如何防止崩溃

How to prevent crash when selecting specific contact using AdressBookUI

我在这条线上崩溃了。

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

如果第一个 phone 数字是 selected,我得到索引 1,这是错误的。它应该是 0,因此选择了错误的数字。如果我 select 第二个数字,它给出的索引为 -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];
}

在处理已删除 phone numbers/emails 的联系人副本时,iOS 8.3(可能是 iOS 8 的早期版本)存在错误。 ABPeoplePickerNavigationController 的文档指出:

In iOS 8 and later bringing up a people-picker navigtion controller does not require the app to have access to a user’s contacts, and the user will not be prompted to grant access. If the app does not itself have access to the user’s contacts, a temporary copy of the contact selected by the user will be returned to the app.

在我的测试中,我有一个具有三个 phone 号码的联系人(我们称它们为 111222333)。 identifier 似乎是固定的、稳定的从零开始的值。因此我的三个 phone 号码是标识符 02。如果 phone 号码被删除,标识符不会改变。从零开始的 indexes 用于访问当前的 phone 号码(或电子邮件等)列表,ABMultiValueGetIndexForIdentifier 用于将标识符转换为索引。

在我的测试中,我删除了第一个 phone 号码 111。这不会更改其余 phone 个号码(222=1333=2)的标识符。

当我使用 ABPeoplePickerNavigationController 并选择第一个 phone 数字 (222) 时,委托方法 peoplePickerNavigationController: didSelectPerson:property:identifier: 正确传递了标识符 1。但是,ABMultiValueGetIndexForIdentifier 返回的索引为 1,而不是 0,然后我的应用程序将 phone 数字 333 复制为它认为用户已选择的那个。如果用户选择 333 然后我被正确传递了一个标识符 2ABMultiValueGetIndexForIdentifier 将其转换为 -1 然后对 ABMultiValueCopyValueAtIndex 的不受保护的调用崩溃了。

因此,在处理联系人的 副本 时(这是 iOS 8 中应用未被授权访问地址簿时发生的情况) , iOS 好像是根据真实的联系方式使用标识符,但是索引是基于副本的。该副本似乎忘记了先前删除的 phone 号码,如果用户选择了在先前删除的 phone 之后创建的 phone 号码,标识符到索引的映射就会出错数字。如果用户没有删除 phone 个号码,或者如果他们删除了 phone 个号码 他们选择的号码之后,它会起作用。

解决方法是通过使用 ABAddressBookRequestAccessWithCompletion 请求用户访问地址簿的权限来使应用复杂化。一旦授予,应用程序将不会获得所选联系人的 副本,并且标识符到索引的映射工作正常。