iOS开发——高级技术&通讯录服务

通讯录服务

AddressBook

iOS中带有一 个Contacts应用程序来管理联系人,但是有些时候我们希望自己的应用能够访问或者修改这些信息,这个时候就要用到 AddressBook.framework框架。iOS中的通讯录是存储在数据库中的,由于iOS的权限设计,开发人员是不允许直接访问通讯录数据库 的,必须依靠AddressBook提供的标准API来实现通讯录操作。通过AddressBook.framework开发者可以从底层去操作 AddressBook.framework的所有信息,但是需要注意的是这个框架是基于C语言编写的,无法使用ARC来管理内存,开发者需要自己管理内 存。下面大致介绍一下通讯录操作中常用的类型:

  • ABAddressBookRef: 代表通讯录对象,通过该对象开发人员不用过多的关注通讯录的存储方式,可以直接以透明的方式去访问、保存(在使用 AddressBook.framework操作联系人时,所有的增加、删除、修改后都必须执行保存操作,类似于Core Data)等。

  • ABRecordRef: 代表一个通用的记录对象,可以是一条联系人信息,也可以是一个群组,可以通过ABRecordGetRecordType()函数获得具体类型。如果作为 联系人(事实上也经常使用它作为联系人),那么这个记录记录了一个完整的联系人信息(姓名、性别、电话、邮件等),每条记录都有一个唯一的ID标示这条记 录(可以通过ABRecordGetRecordID()函数获得)。

  • ABPersonRef:代表联系人信息,很少直接使用,实际开发过程中通常会使用类型为“kABPersonType”的ABRecordRef来表示联系人(由此可见ABPersonRef其实是一种类型为“kABPersonType”的ABRecordRef)

  • ABGroupRef:代表群组,与ABPersonRef类似,很少直接使用ABGroupRef,而是使用类型为“kABGroupType”的ABRecordRef来表示群组,一个群组可以包含多个联系人,一个联系人也同样可以多个群组。

由于通讯录操作的关键是对ABRecordRef的操作,首先看一下常用的操作通讯录记录的方法:

ABPersonCreate():创建一个类型为“kABPersonType”的ABRecordRef。

ABRecordCopyValue():取得指定属性的值。

ABRecordCopyCompositeName():取得联系人(或群组)的复合信息(对于联系人则包括:姓、名、公司等信息,对于群组则返回组名称)。

ABRecordSetValue(): 设置ABRecordRef的属性值。注意在设置ABRecordRef的值时又分为单值属性和多值属性:单值属性设置只要通过 ABRecordSetValue()方法指定属性名和值即可;多值属性则要先通过创建一个ABMutableMultiValueRef类型的变量,然 后通过ABMultiValueAddValueAndLabel()方法依次添加属性值,最后通过ABRecordSetValue()方法将 ABMutableMultiValueRef类型的变量设置为记录值。

ABRecordRemoveValue():删除指定的属性值。

注意由于联系人访问时(读取、设置、删除时)牵扯到大量联系人属性,可以到ABPerson.h中查询或者直接到帮助文档“Personal Information Properties”

通讯录的访问步骤一般如下:

  1. 调用ABAddressBookCreateWithOptions()方法创建通讯录对象ABAddressBookRef。

  2. 调用ABAddressBookRequestAccessWithCompletion()方法获得用户授权访问通讯录。

  3. 调用ABAddressBookCopyArrayOfAllPeople()、ABAddressBookCopyPeopleWithName()方法查询联系人信息。

  4. 读 取联系人后如果要显示联系人信息则可以调用ABRecord相关方法读取相应的数据;如果要进行修改联系人信息,则可以使用对应的方法修改 ABRecord信息,然后调用ABAddressBookSave()方法提交修改;如果要删除联系人,则可以调用 ABAddressBookRemoveRecord()方法删除,然后调用ABAddressBookSave()提交修改操作。

  5. 也 就是说如果要修改或者删除都需要首先查询对应的联系人,然后修改或删除后提交更改。如果用户要增加一个联系人则不用进行查询,直接调用 ABPersonCreate()方法创建一个ABRecord然后设置具体的属性,调用ABAddressBookAddRecord方法添加即可。

下面就通过一个示例演示一下如何通过ABAddressBook.framework访问通讯录,这个例子中通过一个UITableViewController模拟一下通讯录的查看、删除、添加操作。

主控制器视图,用于显示联系人,修改删除联系人:

KCContactViewController.h

 
 1 //

 2 //  KCTableViewController.h

 3 //  AddressBook

 4 //

 5 //  Created by Kenshin Cui on 14/04/05.

 6 //  Copyright (c) 2014年 cmjstudio. All rights reserved.

 7 //

 8 #import

 9 /**

10  *  定义一个协议作为代理

11  */

12 @protocol KCContactDelegate

13 //新增或修改联系人

14 -(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber;

15 //取消修改或新增

16 -(void)cancelEdit;

17 @end

18 @interface KCContactTableViewController : UITableViewController

19 @end

 

KCContactViewController.m

 
  1 //

  2 //  KCTableViewController.m

  3 //  AddressBook

  4 //

  5 //  Created by Kenshin Cui on 14/04/05.

  6 //  Copyright (c) 2014年 cmjstudio. All rights reserved.

  7 //

  8 #import "KCContactTableViewController.h"

  9 #import

 10 #import "KCAddPersonViewController.h"

 11 @interface KCContactTableViewController ()

 12 @property (assign,nonatomic) ABAddressBookRef addressBook;//通讯录

 13 @property (strong,nonatomic) NSMutableArray *allPerson;//通讯录所有人员

 14 @property (assign,nonatomic) int isModify;//标识是修改还是新增,通过选择cell进行导航则认为是修改,否则视为新增

 15 @property (assign,nonatomic) UITableViewCell *selectedCell;//当前选中的单元格

 16 @end

 17 @implementation KCContactTableViewController

 18 #pragma mark - 控制器视图

 19 - (void)viewDidLoad {

 20     [super viewDidLoad];

 21   

 22     //请求访问通讯录并初始化数据

 23     [self requestAddressBook];

 24 }

 25 //由于在整个视图控制器周期内addressBook都驻留在内存中,所有当控制器视图销毁时销毁该对象

 26 -(void)dealloc{

 27     if (self.addressBook!=NULL) {

 28         CFRelease(self.addressBook);

 29     }

 30 }

 31 #pragma mark - UI事件

 32 //点击删除按钮

 33 - (IBAction)trashClick:(UIBarButtonItem *)sender {

 34     self.tableView.editing=!self.tableView.editing;

 35 }

 36 #pragma mark - UITableView数据源方法

 37 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

 38     return 1;

 39 }

 40 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

 41     return self.allPerson.count;

 42 }

 43 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

 44     static NSString *identtityKey=@"myTableViewCellIdentityKey1";

 45     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identtityKey];

 46     if(cell==nil){

 47         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identtityKey];

 48     }

 49     //取得一条人员记录

 50     ABRecordRef recordRef=(__bridge ABRecordRef)self.allPerson[indexPath.row];

 51     //取得记录中得信息

 52     NSString *firstName=(__bridge NSString *) ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);//注意这里进行了强转,不用自己释放资源

 53     NSString *lastName=(__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonLastNameProperty);

 54      

 55     ABMultiValueRef phoneNumbersRef= ABRecordCopyValue(recordRef, kABPersonPhoneProperty);//获取手机号,注意手机号是ABMultiValueRef类,有可能有多条

 56 //    NSArray *phoneNumbers=(__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneNumbersRef);//取得CFArraryRef类型的手机记录并转化为NSArrary

 57     long count= ABMultiValueGetCount(phoneNumbersRef);

 58 //    for(int i=0;i0) {

 59         cell.detailTextLabel.text=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, 0));

 60     }

 61     if(ABPersonHasImageData(recordRef)){//如果有照片数据

 62         NSData *imageData= (__bridge NSData *)(ABPersonCopyImageData(recordRef));

 63         cell.imageView.image=[UIImage imageWithData:imageData];

 64     }else{

 65         cell.imageView.image=[UIImage imageNamed:@"avatar"];//没有图片使用默认头像

 66     }

 67     //使用cell的tag存储记录id

 68     cell.tag=ABRecordGetRecordID(recordRef);

 69      

 70     return cell;

 71 }

 72 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

 73     if (editingStyle == UITableViewCellEditingStyleDelete) {

 74         ABRecordRef recordRef=(__bridge ABRecordRef )self.allPerson[indexPath.row];

 75         [self removePersonWithRecord:recordRef];//从通讯录删除

 76         [self.allPerson removeObjectAtIndex:indexPath.row];//从数组移除

 77         [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];//从列表删除

 78     } else if (editingStyle == UITableViewCellEditingStyleInsert) {

 79         // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view

 80     }   

 81 }

 82 #pragma mark - UITableView代理方法

 83 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

 84     self.isModify=1;

 85     self.selectedCell=[tableView cellForRowAtIndexPath:indexPath];

 86     [self performSegueWithIdentifier:@"AddPerson" sender:self];

 87 }

 88 #pragma mark - Navigation

 89 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

 90     if([segue.identifier isEqualToString:@"AddPerson"]){

 91         UINavigationController *navigationController=(UINavigationController *)segue.destinationViewController;

 92         //根据导航控制器取得添加/修改人员的控制器视图

 93         KCAddPersonViewController *addPersonController=(KCAddPersonViewController *)navigationController.topViewController;

 94         addPersonController.delegate=self;

 95         //如果是通过选择cell进行的导航操作说明是修改,否则为添加

 96         if (self.isModify) {

 97             UITableViewCell *cell=self.selectedCell;

 98             addPersonController.recordID=(ABRecordID)cell.tag;//设置

 99             NSArray *array=[cell.textLabel.text componentsSeparatedByString:@" "];

100             if (array.count>0) {

101                 addPersonController.firstNameText=[array firstObject];

102             }

103             if (array.count>1) {

104                 addPersonController.lastNameText=[array lastObject];

105             }

106             addPersonController.workPhoneText=cell.detailTextLabel.text;

107              

108         }

109     }

110 }

111 #pragma mark - KCContact代理方法

112 -(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{

113     if (self.isModify) {

114         UITableViewCell *cell=self.selectedCell;

115         NSIndexPath *indexPath= [self.tableView indexPathForCell:cell];

116         [self modifyPersonWithRecordID:(ABRecordID)cell.tag firstName:firstName lastName:lastName workNumber:workNumber];

117         [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];

118     }else{

119         [self addPersonWithFirstName:firstName lastName:lastName workNumber:workNumber];//通讯簿中添加信息

120         [self initAllPerson];//重新初始化数据

121         [self.tableView reloadData];

122     }

123     self.isModify=0;

124 }

125 -(void)cancelEdit{

126     self.isModify=0;

127 }

128 #pragma mark - 私有方法

129 /**

130  *  请求访问通讯录

131  */

132 -(void)requestAddressBook{

133     //创建通讯录对象

134     self.addressBook=ABAddressBookCreateWithOptions(NULL, NULL);

135      

136     //请求访问用户通讯录,注意无论成功与否block都会调用

137     ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {

138         if (!granted) {

139             NSLog(@"未获得通讯录访问权限!");

140         }

141         [self initAllPerson];

142          

143     });

144 }

145 /**

146  *  取得所有通讯录记录

147  */

148 -(void)initAllPerson{

149     //取得通讯录访问授权

150     ABAuthorizationStatus authorization= ABAddressBookGetAuthorizationStatus();

151     //如果未获得授权

152     if (authorization!=kABAuthorizationStatusAuthorized) {

153         NSLog(@"尚未获得通讯录访问授权!");

154         return ;

155     }

156     //取得通讯录中所有人员记录

157     CFArrayRef allPeople= ABAddressBookCopyArrayOfAllPeople(self.addressBook);

158     self.allPerson=(__bridge NSMutableArray *)allPeople;

159      

160     //释放资源

161     CFRelease(allPeople);

162 }

163 /**

164  *  删除指定的记录

165  *

166  *  @param recordRef 要删除的记录

167  */

168 -(void)removePersonWithRecord:(ABRecordRef)recordRef{

169     ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//删除

170     ABAddressBookSave(self.addressBook, NULL);//删除之后提交更改

171 }

172 /**

173  *  根据姓名删除记录

174  */

175 -(void)removePersonWithName:(NSString *)personName{

176     CFStringRef personNameRef=(__bridge CFStringRef)(personName);

177     CFArrayRef recordsRef= ABAddressBookCopyPeopleWithName(self.addressBook, personNameRef);//根据人员姓名查找

178     CFIndex count= CFArrayGetCount(recordsRef);//取得记录数

179     for (CFIndex i=0; i!=count; ++i) {

180         ABRecordRef recordRef=CFArrayGetValueAtIndex(recordsRef, i);//取得指定的记录

181         ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//删除

182     }

183     ABAddressBookSave(self.addressBook, NULL);//删除之后提交更改

184     CFRelease(recordsRef);

185 }

186 /**

187  *  添加一条记录

188  *

189  *  @param firstName  名

190  *  @param lastName   姓

191  *  @param iPhoneName iPhone手机号

192  */

193 -(void)addPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{

194     //创建一条记录

195     ABRecordRef recordRef= ABPersonCreate();

196     ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名

197     ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓

198      

199     ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);//添加设置多值属性

200     ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);//添加工作电话

201     ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);

202      

203     //添加记录

204     ABAddressBookAddRecord(self.addressBook, recordRef, NULL);

205      

206     //保存通讯录,提交更改

207     ABAddressBookSave(self.addressBook, NULL);

208     //释放资源

209     CFRelease(recordRef);

210     CFRelease(multiValueRef);

211 }

212 /**

213  *  根据RecordID修改联系人信息

214  *

215  *  @param recordID   记录唯一ID

216  *  @param firstName  姓

217  *  @param lastName   名

218  *  @param homeNumber 工作电话

219  */

220 -(void)modifyPersonWithRecordID:(ABRecordID)recordID firstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{

221     ABRecordRef recordRef=ABAddressBookGetPersonWithRecordID(self.addressBook,recordID);

222     ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名

223     ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓

224      

225     ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);

226     ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);

227     ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);

228     //保存记录,提交更改

229     ABAddressBookSave(self.addressBook, NULL);

230     //释放资源

231     CFRelease(multiValueRef);

232 }

233 @end

 

 

新增或修改控制器视图,用于显示一个联系人的信息或者新增一个联系人:

KCAddPersonViewController.h

 
 1 //

 2 //  KCAddPersonViewController.h

 3 //  AddressBook

 4 //

 5 //  kABPersonFirstNameProperty

 6 //  Copyright (c) 2014年 cmjstudio. All rights reserved.

 7 //

 8 #import

 9 @protocol KCContactDelegate;

10 @interface KCAddPersonViewController : UIViewController

11 @property (assign,nonatomic) int recordID;//通讯录记录id,如果ID不为0则代表修改否则认为是新增

12 @property (strong,nonatomic) NSString *firstNameText;

13 @property (strong,nonatomic) NSString *lastNameText;

14 @property (strong,nonatomic) NSString *workPhoneText;

15 @property (strong,nonatomic) iddelegate;

16 @end

 

 1 //

 2 //  KCAddPersonViewController.m

 3 //  AddressBook

 4 //

 5 //  kABPersonFirstNameProperty

 6 //  Copyright (c) 2014年 cmjstudio. All rights reserved.

 7 //

 8 #import "KCAddPersonViewController.h"

 9 #import "KCContactTableViewController.h"

10 @interface KCAddPersonViewController ()

11 @property (weak, nonatomic) IBOutlet UITextField *firstName;

12 @property (weak, nonatomic) IBOutlet UITextField *lastName;

13 @property (weak, nonatomic) IBOutlet UITextField *workPhone;

14 @end

15 @implementation KCAddPersonViewController

16 - (void)viewDidLoad {

17     [super viewDidLoad];

18     [self setupUI];

19 }

20 #pragma mark - UI事件

21 - (IBAction)cancelClick:(UIBarButtonItem *)sender {

22     [self.delegate cancelEdit];

23     [self dismissViewControllerAnimated:YES completion:nil];

24 }

25 - (IBAction)doneClick:(UIBarButtonItem *)sender {

26     //调用代理方法

27     [self.delegate editPersonWithFirstName:self.firstName.text lastName:self.lastName.text workNumber:self.workPhone.text];

28      

29     [self dismissViewControllerAnimated:YES completion:nil];

30 }

31 #pragma mark - 私有方法

32 -(void)setupUI{

33     if (self.recordID) {//如果ID不为0则认为是修改,此时需要初始化界面

34         self.firstName.text=self.firstNameText;

35         self.lastName.text=self.lastNameText;

36         self.workPhone.text=self.workPhoneText;

37     }

38 }

39 @end

 

KCAddPersonViewController.m

 

运行效果:

备注:

1.上文中所指的以Ref结尾的对象事实上是该对象的指针(或引用),在C语言的框架中多数类型会以Ref结尾,这个类型本身就是一个指针,定义时不需要加“*”。

2.通常方法中包含copy、create、new、retain等关键字的方法创建的变量使用之后需要调用对应的release方法释放。例如:使用ABPersonCreate();创建完ABRecordRef变量后使用CFRelease()方法释放。

3. 在与很多C语言框架交互时可以都存在Obj-C和C语言类型之间的转化(特别是Obj-C和Core Foundation框架中的一些转化),此时可能会用到桥接,只要在强转之后前面加上”__bridge”即可,经过桥接转化后的类型不需要再去手动维 护内存,也就不需要使用对应的release方法释放内存。

4.AddressBook框架中很多类型的创建、属性设置等都是以这个类型名 开发头的方法来创建的,事实上如果大家熟悉了其他框架会发现也都是类似的,这是Apple开发中约定俗成的命名规则(特别是C语言框架)。例如:要给 ABRecordRef类型的变量设置属性则可以通过ABRecordSetValue()方法完成。

AddressBookUI

使 用AddressBook.framework来操作通讯录特点就是可以对通讯录有更加精确的控制,但是缺点就是面对大量C语言API稍嫌麻烦,于是 Apple官方提供了另一套框架供开发者使用,那就是AddressBookUI.framework。例如前面查看、新增、修改人员的界面这个框架就提 供了现成的控制器视图供开发者使用。下面是这个框架中提供的控制器视图:

  • ABPersonViewController:用于查看联系人信息(可设置编辑)。需要设置displayedPerson属性来设置要显示或编辑的联系人。

  • ABNewPersonViewController:用于新增联系人信息。

  • ABUnknownPersonViewController:用于显示一个未知联系人(尚未保存的联系人)信息。需要设置displayedPerson属性来设置要显示的未知联系人。

以 上三个控制器视图均继承于UIViewController,在使用过程中必须使用一个UINavigationController进行包装,否则只能 看到视图内容无法进行操作(例如对于ABNewPersonViewController如果不使用UINavigationController进行包 装则没有新增和取消按钮),同时注意包装后的控制器视图不需要处理具体新增、修改逻辑(增加和修改的处理逻辑对应的控制器视图内部已经完成),但是必须处 理控制器的关闭操作(调用dismissViewControllerAnimated::方法),并且可以通过代理方法获得新增、修改的联系人。下面看 一下三个控制器视图的代理方法:

1.ABPersonViewController的displayViewDelegate代理方法:

-(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:此方法会在选择了一个联系人属性后触发,四个参数分别代 表:使用的控制器视图、所查看的联系人、所选则的联系人属性、该属性是否是多值属性。

2.ABNewPersonViewController的newPersonViewDelegate代理方法:

-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person:点击取消或完成后触发,如果参数中的person为 NULL说明点击了取消,否则说明点击了完成。无论是取消还是完成操作,此方法调用时保存操作已经进行完毕,不需要在此方法中自己保存联系人信息。

3.ABUnkownPersonViewcontroller的unkownPersonViewDelegate代理方法:

-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person:保存此联系人时调用,调用后将此联系人返回。

-(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:选择一个位置联系人属性之后执行,返回值代表是否执行默 认的选择操作(例如如果是手机号,默认操作会拨打此电话)。

除了上面三类控制器视图在AddressBookUI中还提供了另外一个控制器 视图ABPeoplePickerNavigationController,它与之前介绍的UIImagePickerController、 MPMediaPickerController类似,只是他是用来选择一个联系人的。这个控制器视图本身继承于 UINavigationController,视图自身的“组”、“取消”按钮操作不需要开发者来完成(例如开发者不用在点击取消是关闭当前控制器视 图,它自身已经实现了关闭方法),当然这里主要说一下这个控制器视图的peoplePickerDelegate代理方法:

-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person:选择一个联系人后执行。此代理方法实现后代理方法 “-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier”不会再执行。并且一旦实现了这个代理方法用户只能选择到 联系人视图,无法查看具体联系人的信息。

-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker:用户点击取消后执行。

-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:选择联系人具体的属性后执行,注意如果要执行此方法则不 能实现-(void)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person代理方法,此时如果点击一个具体联系人会导航到联系人详细信息界面,用户点击具 体的属性后触发此方法。

下面就看一下上面四个控制器视图的使用方法,在下面的程序中定义了四个按钮,点击不同的按钮调用不同的控制器视图用于演示:

 
  1 //

  2 //  ViewController.m

  3 //  AddressBookUI

  4 //

  5 //  Created by Kenshin Cui on 14/04/05.

  6 //  Copyright (c) 2014年 cmjstudio. All rights reserved.

  7 //

  8 #import "ViewController.h"

  9 #import

 10 @interface ViewController ()

 11 @end

 12 @implementation ViewController

 13 - (void)viewDidLoad {

 14     [super viewDidLoad];

 15 }

 16 #pragma mark - UI事件

 17 //添加联系人

 18 - (IBAction)addPersonClick:(UIButton *)sender {

 19     ABNewPersonViewController *newPersonController=[[ABNewPersonViewController alloc]init];

 20     //设置代理

 21     newPersonController.newPersonViewDelegate=self;

 22     //注意ABNewPersonViewController必须包装一层UINavigationController才能使用,否则不会出现取消和完成按钮,无法进行保存等操作

 23     UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:newPersonController];

 24     [self presentViewController:navigationController animated:YES completion:nil];

 25 }

 26 //

 27 - (IBAction)unknownPersonClick:(UIButton *)sender {

 28     ABUnknownPersonViewController *unknownPersonController=[[ABUnknownPersonViewController alloc]init];

 29     //设置未知人员

 30     ABRecordRef recordRef=ABPersonCreate();

 31     ABRecordSetValue(recordRef, kABPersonFirstNameProperty, @"Kenshin", NULL);

 32     ABRecordSetValue(recordRef, kABPersonLastNameProperty, @"Cui", NULL);

 33     ABMultiValueRef multiValueRef=ABMultiValueCreateMutable(kABStringPropertyType);

 34     ABMultiValueAddValueAndLabel(multiValueRef, @"18500138888", kABHomeLabel, NULL);

 35     ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);

 36     unknownPersonController.displayedPerson=recordRef;

 37     //设置代理

 38     unknownPersonController.unknownPersonViewDelegate=self;

 39     //设置其他属性

 40     unknownPersonController.allowsActions=YES;//显示标准操作按钮

 41     unknownPersonController.allowsAddingToAddressBook=YES;//是否允许将联系人添加到地址簿

 42      

 43     CFRelease(multiValueRef);

 44     CFRelease(recordRef);

 45     //使用导航控制器包装

 46     UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:unknownPersonController];

 47     [self presentViewController:navigationController animated:YES completion:nil];

 48 }

 49 - (IBAction)showPersonClick:(UIButton *)sender {

 50     ABPersonViewController *personController=[[ABPersonViewController alloc]init];

 51     //设置联系人

 52     ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, NULL);

 53     ABRecordRef recordRef= ABAddressBookGetPersonWithRecordID(addressBook, 1);//取得id为1的联系人记录

 54     personController.displayedPerson=recordRef;

 55     //设置代理

 56     personController.personViewDelegate=self;

 57     //设置其他属性

 58     personController.allowsActions=YES;//是否显示发送信息、共享联系人等按钮

 59     personController.allowsEditing=YES;//允许编辑

 60 //    personController.displayedProperties=@[@(kABPersonFirstNameProperty),@(kABPersonLastNameProperty)];//显示的联系人属性信息,默认显示所有信息

 61      

 62     //使用导航控制器包装

 63     UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:personController];

 64     [self presentViewController:navigationController animated:YES completion:nil];

 65 }

 66 - (IBAction)selectPersonClick:(UIButton *)sender {

 67     ABPeoplePickerNavigationController *peoplePickerController=[[ABPeoplePickerNavigationController alloc]init];

 68     //设置代理

 69     peoplePickerController.peoplePickerDelegate=self;

 70     [self presentViewController:peoplePickerController animated:YES completion:nil];

 71 }

 72 #pragma mark - ABNewPersonViewController代理方法

 73 //完成新增(点击取消和完成按钮时调用),注意这里不用做实际的通讯录增加工作,此代理方法调用时已经完成新增,当保存成功的时候参数中得person会返回保存的记录,如果点击取消person为NULL

 74 -(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person{

 75     //如果有联系人信息

 76     if (person) {

 77         NSLog(@"%@ 信息保存成功.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));

 78     }else{

 79         NSLog(@"点击了取消.");

 80     }

 81     //关闭模态视图窗口

 82     [self dismissViewControllerAnimated:YES completion:nil];

 83      

 84 }

 85 #pragma mark - ABUnknownPersonViewController代理方法

 86 //保存未知联系人时触发

 87 -(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person{

 88     if (person) {

 89         NSLog(@"%@ 信息保存成功!",(__bridge NSString *)(ABRecordCopyCompositeName(person)));

 90     }

 91     [self dismissViewControllerAnimated:YES completion:nil];

 92 }

 93 //选择一个人员属性后触发,返回值YES表示触发默认行为操作,否则执行代理中自定义的操作

 94 -(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{

 95     if (person) {

 96         NSLog(@"选择了属性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));

 97     }

 98     return NO;

 99 }

100 #pragma mark - ABPersonViewController代理方法

101 //选择一个人员属性后触发,返回值YES表示触发默认行为操作,否则执行代理中自定义的操作

102 -(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{

103     if (person) {

104          NSLog(@"选择了属性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));

105     }

106     return NO;

107 }

108 #pragma mark - ABPeoplePickerNavigationController代理方法

109 //选择一个联系人后,注意这个代理方法实现后属性选择的方法将不会再调用

110 -(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person{

111     if (person) {

112         NSLog(@"选择了%@.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));

113     }

114 }

115 //选择属性之后,注意如果上面的代理方法实现后此方法不会被调用

116 //-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{

117 //    if (person && property) {

118 //        NSLog(@"选择了属性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));

119 //    }

120 //}

121 //点击取消按钮

122 -(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{

123     NSLog(@"取消选择.");

124 }

125 @end

 

运行效果:

2.png

3.png

注意为了让大家可以更加清楚的看到几个控制器视图的使用,这里并没有结合前面的UITableViewController来使用,事实上大家结合前面UITableViewController可以做一个完善的通讯录应用。

 

你可能感兴趣的:(ios开发)