How to prevent crash when selecting specific contact using AdressBookUI

转载自http://ambracode.com/index/show/291216



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

There is a bug in iOS 8.3 (and presumably previous version of iOS 8) when working on copies of contacts that have had phone numbers/emails removed. The documentation forABPeoplePickerNavigationController states that:

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.

In my testing I had a contact which had three phone numbers (let's call them 111, 222 and 333). It appears that identifiers are fixed, stable zero-based values. Thus my three phone numbers were identifier0 to 2. If a phone number is deleted the identifiers do not change. Zero-basedindexes are used to access the current list of phone numbers (or emails etc.) andABMultiValueGetIndexForIdentifier is used to convert an identifier into an index.

In my test I deleted the first phone number, 111. This does not change the identifiers for the remaining phone numbers (222=1,333=2).

When I used ABPeoplePickerNavigationController and chose the first phone number (222) the delegate methodpeoplePickerNavigationController: didSelectPerson:property:identifier: correctly passed an identifier of1. However, ABMultiValueGetIndexForIdentifier returned an index of 1, not 0 and my app then copied the phone number333 as the one it thought the user had selected. If the user picked 333 then I was correctly passed an identifier of 2 but ABMultiValueGetIndexForIdentifier converted that to -1 and then an unprotected call toABMultiValueCopyValueAtIndex crashed.

So, when working on a copy of the contact (which is what happens in iOS 8 when the app has not been authorised to access the address book), iOS seems to be using identifiers based on the real contact, but indexes are based on the copy. The copy seems to have forgotten the previously-deleted phone number and the identifier-to-index mapping goes wrong if the user picks a phone number that was created after a previously-deleted phone number. It works if the user hasn't deleted phone numbers, or if they have deleted phone numbers after the one they pick.

The workaround is to complicate the app by making it ask the user for permission to access the Address Book usingABAddressBookRequestAccessWithCompletion. Once granted, the app will not be given acopy of the selected contact and the identifier-to-index mapping works correctly.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值