iOS开发------操作通讯录(AddressBook篇)&通讯录UI(AddressBookUI篇)

上篇博文简要的介绍了如何使用AddessBook.framework来获取系统通讯录,但有时候又想对其做修改怎么办,那么这篇博文就总结一下如何修改系统的通讯录吧。

代码GitHub:https://github.com/YRunIntoLove/YAddressBookUIDemo

修改系统通讯录的方法

两种方法

  1. 通过AddressBook.framework的各种函数来完成对AddressBook的操作。
  2. 通过AddressBookUI.framework中提供的系统UIViewController完成对AddressBook的操作,我们只需要使用这几个控制器,传入相应的参数并实现响应的协议方法就可以完成。

方法看法

以上两种方法,初学者估计不会有人想用第一种,那么个人就来谈谈对这两种方法的看法:

  1. 方法比较繁琐,需要一定量的代码来完成,适合自定义UI布局来完成,相对的比较灵活。
  2. 仅需要弹出系统的控制器,传入相应的参数并实现协议方法,就可以完成对通讯录的操作,代码量较少,但UI会固定成系统通讯录的样式,用法简单但布局不灵活。

通过AddressBook.framework实现

实例化对象

实例化一个需要添加的Person属性,当然,如果是修改,那么就获取该属性喽,怎么获取可是上一篇博文介绍的呢

//实例化一个Person数据
ABRecordRef person = ABPersonCreate();

//这里因为没有addressBook属性,所以需要创建一个
ABAddressBookRef addressBook = ABAddressBookCreate();

//实例化一个CFErrorRef属性,如果实例化,下面的设置为NULL即可
CFErrorRef error = NULL;

修改联系人属性的方法

/**
*   新增或修改(覆盖原值的过程)ABRecordRef中某个属性的方法
*
*   record   新增或修改属性的person实例
*   property 属性的key值,比如kABPersonFirstNameProperty..
*/
bool ABRecordSetValue(ABRecordRef record, ABPropertyID property, CFTypeRef value, CFErrorRef* error);

/**
*   删除ABRecordRef中某个属性的方法
*
*   record   删除属性的person实例
*   property 属性的key值,比如kABPersonFirstNameProperty..
*/
bool ABRecordRemoveValue(ABRecordRef record, ABPropertyID property, CFErrorRef* error);

修改通讯录的方法


//添加联系人的方法
bool ABAddressBookAddRecord(ABAddressBookRef addressBook, ABRecordRef record, CFErrorRef* error);

//删除联系人的方法
bool ABAddressBookRemoveRecord(ABAddressBookRef addressBook, ABRecordRef record, CFErrorRef* erro);

修改完毕

//添加联系人
if (ABAddressBookAddRecord(addressBook, person, &error) == true)
{
    //成功就需要保存一下
    ABAddressBookSave(addressBook, &error);
}

//不要忘记了释放资源
CFRelease(person);
CFRelease(addressBook);

具体实例

添加联系人的姓名属性


/*添加联系人姓名属性*/
ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFStringRef)@"Wen", &error);       //名字
ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFStringRef)@"Yue", &error);        //姓氏
ABRecordSetValue(person, kABPersonMiddleNameProperty,(__bridge CFStringRef)@"YW", &error);        //名字中的信仰名称(比如Jane·K·Frank中的K
ABRecordSetValue(person, kABPersonPrefixProperty,(__bridge CFStringRef)@"W", &error);             //名字前缀
ABRecordSetValue(person, kABPersonSuffixProperty,(__bridge CFStringRef)@"Y", &error);             //名字后缀
ABRecordSetValue(person, kABPersonNicknameProperty,(__bridge CFStringRef)@"", &error);            //名字昵称
ABRecordSetValue(person, kABPersonFirstNamePhoneticProperty,(__bridge CFStringRef)@"Wen", &error);//名字的拼音音标
ABRecordSetValue(person, kABPersonLastNamePhoneticProperty,(__bridge CFStringRef)@"Yue", &error); //姓氏的拼音音标
ABRecordSetValue(person, kABPersonMiddleNamePhoneticProperty,(__bridge CFStringRef)@"Y", &error); //英文信仰缩写字母的拼音音标

添加联系人类型属性

/*添加联系人类型属性*/
ABRecordSetValue(person, kABPersonKindProperty, kABPersonKindPerson, &error);      //设置为个人类型
ABRecordSetValue(person, kABPersonKindProperty, kABPersonKindOrganization, &error);//设置为公司类型

添加联系人头像属性

/*添加联系人头像属性*/
ABPersonSetImageData(person, (__bridge CFDataRef)(UIImagePNGRepresentation([UIImage imageNamed:@""])),&error);//设置联系人头像

添加联系人电话信息

/*添加联系人电话信息*/
//实例化一个多值属性
ABMultiValueRef phoneMultiValue = ABMultiValueCreateMutable(kABMultiStringPropertyType);

//设置相关标志位,也可以不设置,下面的方法写NULL即可
ABMultiValueIdentifier MobileIdentifier;    //手机
ABMultiValueIdentifier iPhoneIdentifier;    //iPhone
ABMultiValueIdentifier MainIdentifier;      //主要
ABMultiValueIdentifier HomeFAXIdentifier;   //家中传真
ABMultiValueIdentifier WorkFAXIdentifier;   //工作传真
ABMultiValueIdentifier OtherFAXIdentifier;  //其他传真
ABMultiValueIdentifier PagerIdentifier;     //传呼

//设置相关数值
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551211", kABPersonPhoneMobileLabel, &MobileIdentifier);    //手机
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551212", kABPersonPhoneIPhoneLabel, &iPhoneIdentifier);    //iPhone
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551213", kABPersonPhoneMainLabel, &MainIdentifier);        //主要
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551214", kABPersonPhoneHomeFAXLabel, &HomeFAXIdentifier);  //家中传真
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551215", kABPersonPhoneWorkFAXLabel, &WorkFAXIdentifier);  //工作传真
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551216", kABPersonPhoneOtherFAXLabel, &OtherFAXIdentifier);//其他传真
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"5551217", kABPersonPhonePagerLabel, &PagerIdentifier);      //传呼

//自定义标签
ABMultiValueAddValueAndLabel(phoneMultiValue, (__bridge CFStringRef)@"55512118", (__bridge CFStringRef)@"自定义", &PagerIdentifier);//自定义标签

//添加属性
ABRecordSetValue(person, kABPersonPhoneProperty, phoneMultiValue, &error);

//释放资源
CFRelease(phoneMultiValue);

添加联系人的工作信息

/*添加联系人的工作信息*/
ABRecordSetValue(person, kABPersonOrganizationProperty, (__bridge CFStringRef)@"OYue", &error);//公司(组织)名称
ABRecordSetValue(person, kABPersonDepartmentProperty, (__bridge CFStringRef)@"DYue", &error);  //部门
ABRecordSetValue(person, kABPersonJobTitleProperty, (__bridge CFStringRef)@"JYue", &error);    //职位

添加联系人的邮件信息

/*添加联系人的邮件信息*/
//实例化多值属性
ABMultiValueRef emailMultiValue = ABMultiValueCreateMutable(kABMultiStringPropertyType);

//设置相关标志位
ABMultiValueIdentifier QQIdentifier;//QQ

//进行赋值
//设置自定义的标签以及值
ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFStringRef)@"[email protected]", (__bridge CFStringRef)@"QQ", &QQIdentifier);

//添加属性
ABRecordSetValue(person, kABPersonEmailProperty, emailMultiValue, &error);

//释放资源
CFRelease(emailMultiValue);

添加联系人的地址信息

/*添加联系人的地址信息*/
//实例化多值属性
ABMultiValueRef addressMultiValue = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);

//设置相关标志位
ABMultiValueIdentifier AddressIdentifier;

//初始化字典属性
CFMutableDictionaryRef addressDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);

//进行添加
CFDictionaryAddValue(addressDictionaryRef, kABPersonAddressCountryKey, (__bridge CFStringRef)@"China");      //国家
CFDictionaryAddValue(addressDictionaryRef, kABPersonAddressCityKey, (__bridge CFStringRef)@"WeiFang");       //城市
CFDictionaryAddValue(addressDictionaryRef, kABPersonAddressStateKey, (__bridge CFStringRef)@"ShangDong");    //省(区)
CFDictionaryAddValue(addressDictionaryRef, kABPersonAddressStreetKey, (__bridge CFStringRef)@"Street");      //街道
CFDictionaryAddValue(addressDictionaryRef, kABPersonAddressZIPKey, (__bridge CFStringRef)@"261500");         //邮编
CFDictionaryAddValue(addressDictionaryRef, kABPersonAddressCountryCodeKey, (__bridge CFStringRef)@"ISO");    //ISO国家编码

//添加属性
ABMultiValueAddValueAndLabel(addressMultiValue, addressDictionaryRef, (__bridge CFStringRef)@"主要", &AddressIdentifier);
ABRecordSetValue(person, kABPersonAddressProperty, addressMultiValue, &error);

//释放资源
CFRelease(addressMultiValue);

添加联系人的生日信息

//添加公历生日
ABRecordSetValue(person, kABPersonBirthdayProperty, (__bridge CFTypeRef)([NSDate date]), &error);

常用的属性如上,其他的属性在此也就不多余了,就是一堆代码的重复,但所有的用法在上面的实例中也都已经给出,只需按照方法用即可。

通过AddressBookUI.framwork实现

ABNewPersonViewController(添加联系人控制器)

顾名思义,它就是用来新增加联系人的控制器,样式就是系统通讯录下的样式,如下:

这里重点的介绍一下它的协议方法,感觉最管用的也就是这个协议方法<ABNewPersonViewControllerDelegate>:

/**
 *  新增联系人点击Cancel或者Done之后的回调方法
 *
 *  @param newPersonView 调用该方法的ABNewPersonViewController对象
 *  @param person        传出的ABRecordRef属性
 *                       点击了Done,person就是新增的联系人属性
 *                       点击了Cancel,person就是NULL
 */
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
       didCompleteWithNewPerson:(nullable ABRecordRef)person;

楼主程序的实例

#pragma mark - <ABNewPersonViewControllerDelegate>

- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(nullable ABRecordRef)person
{
    //表示取消了
    if (person == NULL){
       //Cancle coding..
    }

    //表示保存成功
    else{
       //Cancle Done..
       [self requestContacts];
    }

    //不管成功与否,都需要跳回,因为我是通过模态跳入,所以需要dismiss
    [newPersonView dismissViewControllerAnimated:true completion:^{}];
}

ABUnknownPersonViewController(未知联系人的控制器)

这个控制器刚开始接触的时候,完全有点不懂它的用处,明明有了ABNewPersonViewController,怎么还需要这个,后来发现,它还是有他的作用的,这里先不给大家看图,先看一下初始化的代码:

//实例化一个person
ABRecordRef person = ABPersonCreate();

//设置姓名
ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFStringRef)@"firstName", NULL);

//初始化未知联系人的控制器
ABUnknownPersonViewController * unknowPersonViewController = [[ABUnknownPersonViewController alloc]init];

//设置代理
unknowPersonViewController.unknownPersonViewDelegate = self;

//设置相关属性
unknowPersonViewController.alternateName = @"alternateName";//替代名和姓的替代符
unknowPersonViewController.displayedPerson = person;        //展示的person对象
unknowPersonViewController.message = @"message";            //存在替代符下面的信息
unknowPersonViewController.allowsActions = true;            //是否允许作用(出现共享联系人等)
unknowPersonViewController.allowsAddingToAddressBook = true;//是否允许添加到通讯录(新建或添加到现有联系人)

//释放资源
CFRelease(person);

//push..
[self.navigationController pushViewController:unknowPersonViewController animated:true];

初始化代码如上,那么再来看一下效果图,从下图来看,它不只能够新增联系人,还可以补充现有的联系人:

最后介绍一下他的协议方法,说实话,他的协议方法通过文档看懂了,但是用起来很奇怪,来看一下它的协议<ABUnknownPersonViewControllerDelegate>

/**
 *  当创建新的联系人或者更新到已存在的联系人时调用的方法
 *
 *  @param unknownCardViewController 调用方法的ABUnknownPersonViewController对象
 *  @param person                    创建或者更新的ABRecordRef属性
 */
- (void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController
                 didResolveToPerson:(nullable ABRecordRef)person;

//根据页面选择的属性进行响应判断,与下面的ABPersonViewController协议方法相似
- (BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController
shouldPerformDefaultActionForPerson:(ABRecordRef)person
                           property:(ABPropertyID)property
                         identifier:(ABMultiValueIdentifier)identifier;

ABPersonViewController(详细信息的控制器)

这个控制器主要是用来显示联系人详细信息,不仅如此,还可以对联系人进行编辑,先上图来看看他的样式

它的的可设置属性如下:

//展示详情的Person
@property(nonatomic,readwrite) ABRecordRef displayedPerson;

//是否允许编辑,如果设置为false,右上角的Edit按钮就会消失,默认为true
@property(nonatomic) BOOL allowsEditing;

//是否允许响应,如果设置为false,下面"发送信息,共享联系人"选项就会消失,默认为true
@property(nonatomic) BOOL allowsActions;

//固定展示属性的key数组,只作用于浏览时,比如只想展示姓名,如果进入编辑状态,那么还是会全部展示出来
@property(nonatomic,copy,nullable) NSArray<NSNumber*> *displayedProperties;

//是否显示链接人,默认为false
@property(nonatomic) BOOL shouldShowLinkedPeople;

//设置属性的高亮项,如果属性值是单一的,后面的多值标识符将会被忽略
- (void)setHighlightedItemForProperty:(ABPropertyID)property
                       withIdentifier:(ABMultiValueIdentifier)identifier;

协议方法<ABPersonViewControllerDelegate>

/**
 *  根据页面选择的属性进行响应判断
 *
 *  @param personViewController 进行回调的ABPersonViewController对象
 *  @param person               展示的Person
 *  @param property             进行响应的属性
 *  @param identifier           如果是多值属性,返回多值属性
 *
 *  @return 是否响应,true为按照系统默认方式响应,false为不响应
 */
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
                    property:(ABPropertyID)property
                  identifier:(ABMultiValueIdentifier)identifier;

下面是楼主的协议实例:

- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
                    property:(ABPropertyID)property
                  identifier:(ABMultiValueIdentifier)identifier
{
    //如果点击的是电话选项,不进行响应,就是在真机中,点击电话cell,不会相应拨打电话
    if (property == kABPersonPhoneProperty)
    {
        return false;
    }

    return true;
}

ABPeoplePickerNavigationController(选择联系人的控制器)

是顾名思义的一个选择控制器,因为是导航控制器,所以这里我选择的使用模态跳,直接来看看效果图吧:

它的协议方法如下<ABPeoplePickerNavigationControllerDelegate>(备注:楼主用的Xcode版本号为7.3.1,并且没有下载iOS7.0的模拟环境,所以只能走iOS8.0之后的协议方法)

/**
 *  点击Cancle进行的回调
 *
 *  @param peoplePicker 进行回调的ABPeoplePickerNavigationController
 */
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;
{
    //模态弹回
    [peoplePicker dismissViewControllerAnimated:true completion:^{}];
}
/**
 *  选择了联系人之后进行何种操作的回调(iOS8.0之后由下面的方法替代)
 *
 *  @param peoplePicker 进行回调的ABPeoplePickerNavigationController对象
 *  @param person       选择的Person
 *
 *  @return true表示能够显示通讯录并dismiss掉选择器,false表示不做任何事
 */
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person NS_DEPRECATED_IOS(2_0, 8_0)
{
    return false;
}

/**
 *  选择了联系人之后进行的回调(替代上面协议方法的方法,在iOS8.0之后可用)
 *
 *  或者用属性predicateForSelectionOfPerson来替代
 *
 *  @param peoplePicker 进行回调的ABPeoplePickerNavigationController对象
 *  @param person       选择的Person
 */
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker
                         didSelectPerson:(ABRecordRef)person
{
    //coding record the person

    //dismiss掉选择器
    [peoplePicker dismissViewControllerAnimated:true completion:^{}];

}
/**
 *  选择了联系人之后选择属性时进行何种操作的回调(iOS8.0之后用下面的方法替代)
 *
 * (peoplePickerNavigationController:shouldContinueAfterSelectingPerson: 的详细版)
 *
 *  @param peoplePicker 进行回调的ABPeoplePickerNavigationController对象
 *  @param person       选择的person对象
 *  @param property     选择的属性
 *  @param identifier   如果是多值,传出多值属性,单值属性时可以忽略
 *
 *  @return true表示进行系统的默认操作并dismiss出选择器,false表示在当前选择器显示该联系人
 */
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier NS_DEPRECATED_IOS(2_0,8_0)
{
    return false;
}

/**
 *  选择了联系人之后选择属性时进行何种操作的回调(替代上面协议方法的方法,在iOS8.0之后可用)
 *
 *  或者用属性predicateForSelectionOfProperty来替代
 *
 *  @param peoplePicker 进行回调的ABPeoplePickerNavigationController对象
 *  @param person       选择的person对象
 *  @param property     选择的属性
 *  @param identifier   如果是多值,传出多值属性,单值属性时可以忽略
 */
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker
                         didSelectPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{
    //跳回
    [peoplePicker dismissViewControllerAnimated:true completion:^{}];
}
时间: 2024-12-12 02:34:02

iOS开发------操作通讯录(AddressBook篇)&通讯录UI(AddressBookUI篇)的相关文章

IOS开发中使用CNContact对通讯录增删改查

IOS开发中使用CNContact对通讯录增删改查 首先当然是把CNcontact包含在工程中: 1 @import Contacts; 1.下面是增加联系人的程序段: 1 CNMutableContact * contact = [[CNMutableContact alloc]init]; 2 contact.imageData = UIImagePNGRepresentation([UIImage imageNamed:@"22"]); 3 //设置名字 4 contact.gi

iOS开发 GET、POST请求方法:NSURLConnection篇

Web Service使用的主要协议是HTTP协议,即超文本传输协议. HTTP/1.1协议共定义了8种请求方法(OPTIONS.HEAD.GET.POST.PUT.DELETE.TRACE.CONNECT)作为Web服务器. GET方法,是向指定的资源发送请求,请求的参数“显式”地在URL的后面.有点像明信片,把内容“显式”写在外面,因此安全性比较差.一般使用于读取数据.例如从服务器读取静态图片.或查询数据等. POST方法,是向指定资源提交数据,请求服务器进行处理,数据包含在请求体中.参数和

iOS开发 GET、POST请求方法(NSURLConnection篇)

Web Service使用的主要协议是HTTP协议,即超文本传输协议. HTTP/1.1协议共定义了8种请求方法(OPTIONS.HEAD.GET.POST.PUT.DELETE.TRACE.CONNECT)作为Web服务器. GET方法,是向指定的资源发送请求,请求的参数“显式”地在URL的后面.有点像明信片,把内容“显式”写在外面,因此安全性比较差.一般使用于读取数据.例如从服务器读取静态图片.或查询数据等. POST方法,是向指定资源提交数据,请求服务器进行处理,数据包含在请求体中.参数和

iOS开发笔记7:Text、UI交互细节、两个动画效果等

Text主要总结UILabel.UITextField.UITextView.UIMenuController以及UIWebView/WKWebView相关的一些问题. UI细节主要总结界面交互开发中遇到的一些细节问题,包括Masonry部分的问题. 动画介绍最近用到的两个,算是常用级别的,动画这部分之后会专门研究总结下. 最后介绍两个工具及三个Xcode使用设置的问题. 1.Text (1)UILabel显示多行文字并且文字置顶显示 不限制UILabel的高度(宽度需要设置,确定文字何时换行)

iOS开发之使用Storyboard预览UI在不同屏幕上的运行效果

在公司做项目一直使用Storyboard,虽然有时会遇到团队合作的Storyboard冲突问题,但是对于Storyboard开发效率之高还是比较划算的.在之前的博客中也提到过,团队合作使用Storyboard时,避免冲突有效的解决方法是负责UI开发的同事最好每人维护一个Storyboard, 公用的组件使用轻量级的xib或者纯代码来实现.这样不但提高了开发效率,而且可以有效的避免Storyboard的冲突.如果每个人维护一个Storyboard, 遇到冲突了就以你自己的为准就OK了. 言归正传,

iOS开发 GET、POST请求方法:NSURLSession篇

NSURLSession,与NSURLConnection是并列的,且可以支持后台相关的网络操作的新特性:与NSURLConnection不同的是,NSURLSession把NSURLConnection替换成NSURLSession, NSURLSessionConfiguration,NSURLSessionTask. NSURLSession一般分别两部操作:第一,通过NSURLSession的实例创建task:第二,执行task: 而NSURLSessionTask,也就是task,可以

iOS开发- reloadData无效 (子线程更新UI错误)

今天在写一个聊天工具的时候遇到了一个问题. 注册的通知里面, 每当有其他用户发来消息的时候,  UITableView 就要重新更新 [objc] view plaincopy cell.textLabel.textColor = [UIColor redColor]; 使用红色标记cell名字来突出显示新消息.  (当然,, 这只是个demo, 效果比较渣.  正常情况应该是用户头像跳动或者显示新消息条数...) 可是我发现,  调用了这样的更新语句后, UITableVIew里面的数据并没有

iOS开发------简单实现图片多选功能(AssetsLibrary篇)

AssetsLibrary.framework是iOS7.0之前用来获取手机所有的媒体资源的一个静态库,在iOS8.0之后完全可以用Photo.framework来代替,但因为涉及到适配iOS7,所以这个库用的还是比较多的. 实际上,多选图片有很多很好用的第三方,但找到一个完全符合自己需求的第三方也不是那么容易,就算找到,如果不懂,也不是很好修改代码才对,所以了解一下这个库也是很有必要的,这里就记录一下过程中的认识与问题. 如果小伙伴有什么好玩的库,还请介绍一下,很希望能和喜欢钻研技术的你们一起

iOS 开发操作当前控制器的状态栏

/// 返回当前控制器中状态栏的样式. - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } /// 隐藏当前控制器的状态栏 - (BOOL)prefersStatusBarHidden { return YES; } 注意:这两个方法只能写在当前控制器类里面.