使用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];
}

iOS 8.3(大概是以前的iOS 8)中有一个错误,当时已删除了已删除电话号码/电子邮件的联系人的副本。ABPeoplePickerNavigationController的文档指出:

在iOS 8中,随后提出人选导航控制器不需要该应用程序可以访问用户的联系人,并且不会提示用户授予访问权限。如果该应用本身无法访问用户的联系人,则将将用户选择的联系人的临时副本返回到应用程序。

在我的测试中,我有一个有三个电话号码的联系人(我们将其称为111222333)。看来identifier s是固定的,稳定的基于零的值。因此,我的三个电话号码是标识符02。如果删除了电话号码,则标识符不会更改。基于零的index ES用于访问当前电话号码(或电子邮件等)的列表,并且ABMultiValueGetIndexForIdentifier用于将标识符转换为索引。

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

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

因此,在使用联系人的A 副本(这是iOS 8中发生的情况时,该应用程序未被授权访问地址簿),iOS似乎是根据基于标识符的真正的联系人,但索引基于副本。该副本似乎已经忘记了以前删除的电话号码,如果用户选择以前删除的电话号码创建的电话号码,则标识符对索引映射出错。如果用户尚未删除电话号码,或者他们选择的电话之后删除了电话号码

解决方法是通过使用户征求使用ABAddressBookRequestAccessWithCompletion访问通讯簿的权限来使其复杂化。一旦批准,该应用程序将不会获得所选联系人的副本,并且标识符to-index映射正常工作。

最新更新