调用系统通讯录

通常我们在iOS项目中想到通讯录往往有两大方面的需求。一个是让用户自己从通讯录中选择朋友然后我们获取数据完成业务,另一个是项目通过读取用户通讯录信息来完成相应的数据处理,即用户自主行为和应用调取行为。
首先谈一下用户自主调用通讯录。这里我们会使用系统控件ABPeoplePickerNavigationController。由于是用户自主行为,调用它我们无须向用户请求授权。但是ABPeoplePickerNavigationController给我们提供的操作很有限,在界面上我们只能修改一下导航条背景色,标题颜色之类的属性。对我们更有用的数据则是通过ABPeoplePickerNavigationControllerDelegate的相关方法完成的。这里注意一下,iOS8替换了一个代理方法

- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person NS_AVAILABLE_IOS(8_0);

这也是我们获取数据的主要代理方法。此方法可以看到我们唯一可以获得可操作的数据就是(ABRecordRef)person。下面是获取person数据中手机号的实现:

NSString* name = (__bridge_transfer NSString*)ABRecordCopyCompositeName(person);

    //获取联系人电话

    ABMutableMultiValueRef phoneMulti = ABRecordCopyValue(person, kABPersonPhoneProperty);

    NSMutableArray *phones = [[NSMutableArray allocinit];

    int i;

    for (i = 0; i < ABMultiValueGetCount(phoneMulti); i++)

    {

        NSString *aPhone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneMulti, i);

        NSString *aLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(phoneMulti, i);

        if (aPhone.length < 11) {

            break ;

        }

        if([aLabel isEqualToString:@"_$!<Mobile>!$_"]){

            [phones addObject:[self reStringFormatter:aPhone]];

        }else{

            [phones addObject:[self reStringFormatter:aPhone]];

        }

    }

    //解决phoneMulti的内存泄露

    CFRelease(phoneMulti); //AB..... 类不支持ARC,需要手动内存管理,一定要注意内存!

再谈谈应用调取通讯录信息的方式。这里我们需要让用户授权应用调取通讯录的权限,这样我们可以对通讯录进行增删改查操作。具体的,我们使用ABAddressBookRef和其相关的一系列类。注意,他们都不是iOS类,不支持现金常用的ARC自动管理内存,所以要特别注意内存问题,防止内存泄露。
  这里结合韩韩自身的实际应用,谈谈这种调用通讯录的方法。我的目的是读取通讯录,根据已有的手机号码数据查找相应的用户名,然后显示。在ABAddressBookRef系列类中有根据名字查找通讯录单元信息(ABRecordRef)的方法,但是恰好没有根据手机号查找通讯录单元信息的方法。那么只能通过获得通讯录全部信息,然后遍历并比对手机号信息来查找了。
     1)询问用户获得通讯录读取权限:

 if (ABAddressBookRequestAccessWithCompletion != NULL) {    //检查是否是iOS6

        ABAddressBookRef abRef = ABAddressBookCreateWithOptions(NULL, NULL);

        if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {

            //如果该应用从未申请过权限,申请权限

            ABAddressBookRequestAccessWithCompletion(abRef, ^(bool granted, CFErrorRef error) {

                //根据granted参数判断用户是否同意授予权限

                if (granted) {

                    //查询所有,这里我们可以用来进行下一步操作

                }

            });

        } else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {

            //如果权限已经被授予

            //查询所有,这里我们可以用来进行下一步操作

        } else {

            //如果权限被收回,只能提醒用户去系统设置菜单中打开

        }

        if(abRef){

            CFRelease(abRef);

        }

    }

2)获取全部通讯录单元信息(ABRecordRef

ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

    //获取联系人电话

    CFArrayRef allPerson = ABAddressBookCopyArrayOfAllPeople(addressBook);//取全部联系人

3)获取全部通讯录单元信息(获取名字)

ABRecordRef aPerson = CFArrayGetValueAtIndex(allPerson, (CFIndex)i);

        ABMutableMultiValueRef phoneMulti = ABRecordCopyValue(aPerson, kABPersonPhoneProperty);

        //按照汉语姓名规则拼接用户名,因为有前、中、后名,这里要注意

  ABMutableMultiValueRef firstNameMulti = ABRecordCopyValue(aPerson, kABPersonFirstNameProperty);

  ABMutableMultiValueRef middleNameMulti = ABRecordCopyValue(aPerson, kABPersonMiddleNameProperty);

ABMutableMultiValueRef lastNameMulti = ABRecordCopyValue(aPerson, kABPersonLastNameProperty);

    NSString *firsNameString    = [self dealNullString:(__bridge_transfer NSString*)firstNameMulti];

  NSString *middleNameString  = [self dealNullString:(__bridge_transfer NSString*)middleNameMulti];

    NSString *lastNameString    = [self dealNullString:(__bridge_transfer NSString*)la

NSString *nameString = [NSString stringWithFormat:@"%@%@%@",lastNameString,middleNameString,firsNameString]stNameMulti];

4)获取全部通讯录单元信息(获取手机号)

NSMutableArray *phones = [[NSMutableArray alloc] init];

    for (int i = 0; i < ABMultiValueGetCount(phoneMulti); i++)

    {

//phoneMulti 为ABMutableMultiValueRef类型

        NSString *aPhone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneMulti, i);

        NSString *aLabel = (__bridge_transfer NSString*)ABMultiValueCopyLabelAtIndex(phoneMulti, i);

        TBDPRINT(@"PhoneLabel:%@ Phone#:%@",aLabel,aPhone);

        if (aPhone.length < 11) {

            break ;

        }

        if([aLabel isEqualToString:@"_$!<Mobile>!$_"]){

            [phones addObject:[self reStringFormatter:aPhone]];

        }else{

            [phones addObject:[self reStringFormatter:aPhone]];

        }

    }

剩下的就是比对和数据处理了。运用ABAddressBookRef还可以实现写入数据、删除数据的功能。待以后进一步研究。
iOS9系统中,新发现关于通讯录的问题。现象,在调用通讯录的页面,当打开通讯录正常点选某条电话信息后关闭通讯录之后,在某些页面获取当前最上层window的时候,发现获取到了如 remoteKeyWindow 的一个window,为iOS9新发现的状况,这会造成一些window操作的错误。且到现在为止未查到相关资料。为了降低影响,采取了非根本的方式解决,即在关闭通讯录时,取一个当前页面的textField,在关闭通讯录之后取消该textField的第一响应者。经实测,问题得到了解决。但究其根本原因还不知晓。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值