ios-访问通讯录及Core Foundation和Foundation的桥接

本文介绍了如何在iOS应用中访问用户的通讯录,包括使用AddressBook框架获取联系人数据及使用ABPeoplePickerNavigationController展示联系人界面的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有两个框架可以去访问通讯录一个是AddressBook,AddressBookUI。其中在ios9的时候AddressBookUI框架不推荐使用已经废弃。

其中AddressBookUI提供了联系人列表界面和联系人详情界面、和添加联系人。

AddressBook的话就是需要我们自己去搭建界面的,这里面包含的就是纯C语言的API,仅仅只能获取联系人的数据

里面的数据类型大部分都是基于Core Foundation框架的。

注意的是,我们要访问用户的通讯录的话,应该在Info.plist文件中进行配置下,下面这个选项,表示我们需要得到用户的授权才可以去使用

Privacy - Contacts Usage Description
我们可以通过ABAddressBookGetAuthorizationStatus() 这个方法来获取通讯录的状态

这个总共有四个枚举值

    kABAuthorizationStatusNotDetermined = 0,    // 表示用户还没有决定是否授权你的程序进行访问
    kABAuthorizationStatusRestricted,           // 表示ios设备上一些许可的配置阻止程序与通讯录进行交互
    kABAuthorizationStatusDenied,               // 表示用户不允许你访问数据库
    kABAuthorizationStatusAuthorized            // 表示用户已经授权

然后如果我们想展示界面的话,我们可以进行这样的设置,让点击屏幕的时候去跳出通讯录控制器

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
    //1、创建联系人选择控制器
    ABPeoplePickerNavigationController * picker = [ABPeoplePickerNavigationController new];
    //2、设置代理 这里应该去设置的是peoplePickerDelegate,如果我们去设置的是delegate的话,就是去设置UINavigationController的代理了
    picker.peoplePickerDelegate = self;
    //3、模态视图的弹出
    [self presentViewController:picker animated:YES completion:nil];
    
}
跳出的界面如下所示


ABPeoplePickerNavigationControllerDelegate这个协议当中有三个代理方法是需要我们注意的,如下所示

#pragma mark 取消选中联系人的时候调用
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
    NSLog(@"%s",__func__);
}
#pragma mark 选中某一个联系人会调用
//这里需要注意的是在ios7的时候必须要实现这个方法,否则程序会崩溃
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
{
     NSLog(@"%s",__func__);
}
#pragma mark 选中联系人的某个属性的时候会调用
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person 
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{     
     //property代表的其实就是我们点击进去联系人详情里面的属性的ID
     NSLog(@"%s",__func__);
}

有几点需要注意的是 -(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
 这两个方法如果都实现了,就只会调用didSelectPerson的方法,两个方法我们其实只需要实现一个就可以了。

如果我想要实现点击通讯录中的一个联系人就可以得到它的姓名和电话的话,我们可以在-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person这个方法中进行设置,首先我们需要去知道的是ABRecordRef这个是什么类型的,我们可以点进去看到如下所示

/* Base "type" of all "CF objects", and polymorphic functions on them */
typedef const CF_BRIDGED_TYPE(id) void * CFTypeRef;
这个CFTypeRef其实是和id类型是类似的,可以理解成为把void * 包装CFTypeRef

我们可以调用下面的方法进行获取我们点击的联系人的名字person其实我觉得可以理解成就是一条记录

//1、获取名字
    CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    
    //转换成OC中的字符串我们需要去做一个桥接
    NSString *name = (__bridge NSString *)(firstName);
    
    NSLog(@"%@",name);
    //需要注意的是在Core Foundation中我们需要手动的去释放
     CFRelease(firstName);

还有一个方法是直接可以获取姓名的全称的

CFStringRef str = ABRecordCopyCompositeName(person);
    
    NSString * name1=(__bridge NSString *)(str);
    
    NSLog(@"%@",name1);

    CFRelease(firstName);

获取电话号码的话,我们一样的可以在didSelectPerson方法中进行设置,我们可以这么做

//获取电话,因为通讯录中的电话肯定不可能只有一个,所以我们要获取的是一个数组类型的
    ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
 
    //获取电话的个数
    CFIndex count = ABMultiValueGetCount(phones);
    
    //遍历联系人数组
    for(CFIndex i=0;i<count;i++)
    {
     //获取联系电话的标签也就是联系电话的上面那一栏
        NSString * text =(__bridge_transfer NSString *) ABMultiValueCopyLabelAtIndex(phones, i);
        NSLog(@"%@",text);
        
     //获取联系的电话
        NSString * value = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, i));
        
        NSLog(@"%@",value);
    
}
    //这里要去释放
    CFRelease(phones);
    

最后再简单的介绍下Core Foundation和 Foundation进行桥接的方式

Core Foundation 和 Foundation进行桥接有三种方式
 Foundation框架的对象和Core Foundation对象互相转换
 1、(__bridge type) expression) 表示的是如果是Foundation转Core Foundation 就不需要自己去释放,如果是让Foundation暂时的去使用CoreFoundation框架的对象,就需要去释放。

比如说(__bridge CFURLRef _Nonnull)(url) 就是把url对象暂时转换成了Core Foundation的对象

Core Foundation框架的对象转换为Foundation对象

2、(__bridge_transfer Objective-C type)expression) 就是把Core Foundation的框架交给对象的管理权给Foundation框架,也就是说我们不需要再去释放对象了 还有一点需要注意的就是CFBridgingRelease是和transfer的转换是一样的。
 
 最后一种桥接就是将Foundation对象转换成Core Foundation对象
 3、(__bridge_retained CF type)expression) 这个就是将Foundation堆中转换成Core Foundation对象。所有权也发生了改变,所以需要我们自己去释放

还有就是如果我们用过在MRC和ARC中让CoreFoundation中的对象转换成ARC的对象的话其实会发现在MRC中我们是不需要去做桥接了的,因为其实已经帮我们做了一个隐式的桥接,但是在ARC中不行因为ARC不能自动处理core Foundation类型。

如下是示例代码

    NSString *string = @"ssss";

    CFStringRef str1 = (__bridge_retained CFStringRef)string;

    NSLog(@"%@",str1);

    //关于第一个参数传入的一般来说都是NULL或者而是kCFAllocatorDefault,具体什么含义还没太明白
   CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "sdadad", kCFStringEncodingUTF8);
    
    NSString * string = (__bridge_transfer NSString *)str;
    
    NSLog(@"%@",string);



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值