我在这条线上崩溃了。
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中,随后提出人选导航控制器不需要该应用程序可以访问用户的联系人,并且不会提示用户授予访问权限。如果该应用本身无法访问用户的联系人,则将将用户选择的联系人的临时副本返回到应用程序。
在我的测试中,我有一个有三个电话号码的联系人(我们将其称为111
,222
和333
)。看来identifier
s是固定的,稳定的基于零的值。因此,我的三个电话号码是标识符0
到2
。如果删除了电话号码,则标识符不会更改。基于零的index
ES用于访问当前电话号码(或电子邮件等)的列表,并且ABMultiValueGetIndexForIdentifier
用于将标识符转换为索引。
在我的测试中,我删除了第一个电话号码111
。这不会更改其余电话号码的标识符(222=1
,333=2
)。
当我使用ABPeoplePickerNavigationController
并选择第一个电话号码(222
)时,委托方法peoplePickerNavigationController: didSelectPerson:property:identifier:
正确传递了1
的标识符。但是,ABMultiValueGetIndexForIdentifier
返回了1个索引,而不是0,然后我的应用程序复制了电话号码333
,因为它认为用户选择了。如果用户选择了333
,则正确通过了2
的标识符,但是ABMultiValueGetIndexForIdentifier
将其转换为-1
,然后将其转换给ABMultiValueCopyValueAtIndex
崩溃。
因此,在使用联系人的A 副本(这是iOS 8中发生的情况时,该应用程序未被授权访问地址簿),iOS似乎是根据基于标识符的真正的联系人,但索引基于副本。该副本似乎已经忘记了以前删除的电话号码,如果用户选择以前删除的电话号码创建的电话号码,则标识符对索引映射出错。如果用户尚未删除电话号码,或者他们选择的电话之后删除了电话号码。
解决方法是通过使用户征求使用ABAddressBookRequestAccessWithCompletion
访问通讯簿的权限来使其复杂化。一旦批准,该应用程序将不会获得所选联系人的副本,并且标识符to-index映射正常工作。