我在这条线上遇到了崩溃。
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];
}
答案 0 :(得分:2)
在处理已删除电话号码/电子邮件的联系人副本时,iOS 8.3(可能是iOS 8的早期版本)中存在一个错误。 ABPeoplePickerNavigationController
的文档声明:
在iOS 8及更高版本中,启动人员选择器导航控制器不需要应用程序访问用户的联系人,也不会提示用户授予访问权限。如果应用程序本身无法访问用户的联系人,则用户选择的联系人的临时副本将返回给应用程序。
在我的测试中,我有一个有三个电话号码的联系人(我们称之为111
,222
和333
)。似乎identifier
是固定的,基于零的稳定值。因此,我的三个电话号码是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
的无保护呼叫崩溃。< / p>
因此,在处理联系人的副本时(这是iOS 8中当应用程序未被授权访问地址簿时发生的情况),iOS似乎正在使用基于的标识符真正的联系,但索引是基于副本。如果用户选择在先前删除的电话号码之后创建的电话号码,则该副本似乎忘记了先前删除的电话号码并且标识符到索引映射出错。如果用户没有删除电话号码,或者在他们选择的电话号码之后删除了电话号码,它就可以工作。
解决方法是让应用程序通过ABAddressBookRequestAccessWithCompletion
请求用户访问通讯簿的权限来使应用程序复杂化。授予后,将不会为应用程序提供所选联系人的副本,并且标识符到索引的映射也能正常工作。