1

I'm getting crash on this line.

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

If the first phone number is selected I get index of 1 which is wrong. It should be 0 and therefore choses wrong number. If I select second number it gives index of -1 which crashes the app.

#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];
}
4

1 回答 1

2

在处理已删除电话号码/电子邮件的联系人副本时,iOS 8.3(可能是 iOS 8 的早期版本)中存在一个错误。的文档ABPeoplePickerNavigationController指出:

在 iOS 8 及更高版本中,启动人员选择器导航控制器不需要应用程序有权访问用户的联系人,并且不会提示用户授予访问权限。如果应用程序本身无权访问用户的联系人,则用户选择的联系人的临时副本将返回给应用程序。

在我的测试中,我有一个拥有三个电话号码的联系人(我们称他们111222333)。看起来identifiers 是固定的、稳定的基于零的值。因此,我的三个电话号码02. 如果删除电话号码,则标识符不会改变。从零开始的indexes 用于访问当前的电话号码(或电子邮件等)列表,并ABMultiValueGetIndexForIdentifier用于将标识符转换为索引。

在我的测试中,我删除了第一个电话号码,111. 这不会更改剩余电话号码 ( 222=1, 333=2) 的标识符。

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

因此,在处理联系人副本时(这是在 iOS 8 中应用程序未被授权访问地址簿时发生的情况),iOS 似乎使用基于真实联系人的标识符,但索引是基于复制。副本似乎忘记了先前删除的电话号码,并且如果用户选择在先前删除的电话号码之后创建的电话号码,则标识符到索引的映射会出错。如果用户没有删除电话号码,或者他们在他们选择的电话号码之后删除了电话号码,它就可以工作。

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

于 2015-05-27T17:07:56.507 回答