一、快速体验:
1、
#import <AddressBookUI/AddressBookUI.h>
ViewController遵循< ABPeoplePickerNavigation ControllerDelegate
>
相关方法:
- (IBAction)showPicker:(id)sender
{
ABPeoplePickerNavigation Controller
*picker =[[ABPeoplePickerNavigation
Controller alloc] init];
picker.peoplePickerDelegate = self;
[self presentModalViewControll
er:picker animated:YES];
[picker release];
}
相关代理方法:
- (void) peoplePickerNavigationCo ntrollerDidCancel
:(ABPeoplePickerNavigation
Controller *)peoplePicker
{ //这个方法在用户取消选择时调用
[self dismissModalViewControll
erAnimated:YES];
}
- (BOOL) peoplePickerNavigationCo ntroller:(ABPeoplePickerNavigation Controller *)peoplePicker shouldContinueAfterSelec tingPerson:(ABRecordRef)person
{
//这个方法在用户选择了一个person时调用
[self displayPerson:person];
[self dismissModalViewControll
erAnimated:YES];
return NO;
}
- (BOOL) peoplePickerNavigationCo ntroller:(ABPeoplePickerNavigation Controller *)peoplePicker shouldContinueAfterSelec tingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{ //这个方法在用户选择了一个person的属性时调用
return NO;
}
ABRecordRef类型的对象属性:
- (void)displayPerson:( ABRecordRef )person
{//显示一个person
NSString* name =
(__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProper ty);
self.firstName.text = name;
NSString* phone = nil;
ABMultiValueRef
phoneNumbers = ABRecordCopyValue(person,
kABPersonPhoneProperty
);
if (
ABMultiValueGetCount(phoneNumbers)
> 0) {
phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtI ndex(phoneNumbers, 0);
} else {
phone = @"[None]";
}
self.phoneNumber.text = phone;
}
二、Building Blocks:Working with Records and Properties
你需要理解4种类型的对象才能完全与Address Book数据库完全交互:address books,records,single-value properties,和mulitivalue properties。这章讨论数据是如何存储在这些对象中,并描述了与这些对象交互的 函数。
1、Address Books:
Address Books对象允许你与Address Book数据库交互。要使用Address Book,声明一个ABAddressBookRef实例,并用ABAddressBookCreate 函数设置其值。
重要提示:ABAddressBookRef 实例不能在多个线程中共用。每个线程必须有其自己的实例。
在你创建了address book reference之后,你的应用就可以从其中读取数据,并且更改并保存它。要保存更改,使用ABAddressBookSave :函数;要放弃更改,使用ABAddressBookRevert 。要检查是否有未保存的更改,使用ABAddressBookHasUnsavedC
hanges.
下面是例子:
ABAddressBookRef addressBook ;
bool wantToSaveChanges = YES;
bool didSave;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
if (ABAddressBookHasUnsavedC
hanges(addressBook)) {
if (wantToSaveChanges) {
didSave = ABAddressBookSave(addressBook, &error);
if (!didSave) {}
} else {
ABAddressBookRevert(addressBook);
}
}
CFRelease(addressBook);
在另一个应用或另一个线程对Address Book Database做出更改时,你的应用程序可以请求接收一个通知。一般地,如果你正在显示已经存在的联系人并且你想更新UI来反应联系人的更改,那么你应该注册一个通知。
使用函数ABAddressBookRegisterExt
ernalChangeCallback来注册一个原型为ABExternalChangeCallback
类型的函数。你或许会多次调用ABAddressBookRegisterExt
ernalChangeCallback来注册多个callbacks。使用ABAddressBookUnregisterE
xternalChangeCallback来取消注册。
当你接收到一个change callback,你需要做两件事:如果你没有未保存的更改,你的代码应该简单地revert(恢复)你的address book来得到最新的数据。如果你有未保存的更改,你可能不想恢复并丢失这些更改。如果你应该保存,Address Book Database会尽力merge你的更改和外部的更改。但是,如果更改不能合并或保存失败,你应该准备好其它的动作。
2、Records:
在Address Book 数据库里,信息被存储到records里,使用ABRecordRef表示。每个record表示一个联系人或一个组。函数ABRecordGetRecordType 返回kABPersonType 表示这是联系人,返回kABGroupType表示这是一个组。熟悉Mac OS的Address Book技术的开发者应该注意没有单独的类来区分records的类型;person对象和group对象都是一个类的实例。
重要提示:Record对象不能在线程间安全传递。取而代之的,你应该传递相应的record identifer。
record可以在Address Book 数据库之外存在。这使得他们在存储联系人信息时很有用。
在一个Record内部,数据被存储为属性的集合。group和person对象的可用属性是不一样的,但是 访问他们的函数一样。函数ABRecordCopyValue 和ABRecordSetValue 用来读取和设置属性。ABRecordRemoveValue 用来移除属性。
3、Person Records:
Person Record有单值属性和多值属性。例如first name和last nam e是单值属性,street address和phone number是多值属性。属性名可以通过kABPersonPhoneProperty这样的常量来获得,例如:
NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProper ty);
NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty );
if (
ABMultiValueGetCount(phoneNumbers)
> 0) {
phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtI ndex(phoneNumbers, 0);
...
4、Group Records:
Group Records只有一个属性,kABGroupNameProperty,表示组的名称。要获得属于这个组的所有联系人,使用ABGroupCopyArrayOfAllMem
bers或ABGroupCopyArrayOfAllMem
bersWithShortOrdering,它返回一个包含ABRecordRef的CFArrayRef对象
。
5、属性:
1)单值属性:
ABRecordRef aRecord = ABPersonCreate();
CFErrorRef anError = NULL;
bool didSet;
didSet = ABRecordSetValue(aRecord, kABPersonFirstNameProper ty, CFSTR("Katie"), &anError);
if (!didSet) {}
didSet = ABRecordSetValue (aRecord, kABPersonLastNamePropert
y
, CFSTR("Bell"), &anError);
if (!didSet) {}
CFStringRef firstName, lastName;
firstName = ABRecordCopyValue(aRecord, kABPersonFirstNameProper
ty);
lastName
= ABRecordCopyValue(aRecord, kABPersonLastNamePropert
y);
CFRelease(aRecord);
CFRelease(firstName);
CFRelease(lastName);
2)多值属性:
多值属性由一组值组成,每个值拥有一个text label和一个 相关的identifier。相同的label可以有多个value,但是identifier是唯一的。
例如,下图显示了一个电话号码属性。这里,一个联系人有多个电话号码 ,每个电话号码都有一个text label ,例如home或work,并且有一个identifier。注意,这个例子有2个家庭电话,他们有相同的label, 但是有不 同的identifier。
一个多值属性的每个单独的值可以通过index或identifier 来获取。使用函数ABMultiValueGetIndexForI
dentifier
和ABMultiValueGetIdentifie
rAtIndex.
要保持多值属性中的某一个特定值,就存储它的identifier。因为index会变,但identifier不会变,除非设备变了。
ABMultiValueCopyLabelAtI
ndex和ABMultiValueCopyValueAtI
ndex来拷贝单独的值
ABMultiValueCopyArrayOfA
llValues拷贝所有的值到一个数组中。
3)可变多值属性:
Multivalue对象是不可变的,要更改它你需要创建一个可变的拷贝 ,通过函数ABMultiValueCreateMutabl
eCopy
。你也可以通过ABMultiValueCreatteMutab
le
来创建一个新的可变multivalue对象。
下面的函数用来更改可变MultiValue的属性:
ABMultiValueAddValueAndL
abel
和ABMultiValueInsertValueA
ndLabelAtIndex
来增加属性
ABMultiValueReplaceValue
AtIndex和ABmultiValueReplaceLabel
AtIndex来修改属性
ABmultiValueRemoveValueA
ndLabelAtIndex来移除属性
下面是例子:
ABMutableMultiValueRef multi = ABMultiValueCreateMutabl
e(kABMultiStringPropertyTy
pe);
CFErrorRef anError = NULL;
ABMultiValueIdentifier multivalueIdentifier;
bool didAdd, didSet;
// Here, multivalueIdentifier is just for illustration purposes; it isn't
// used later in the listing.
Real-world code can use this identifier to
// reference the newly-added value.
didAdd = ABMultiValueAddValueAndL
abel(multi, @"(555) 555-1234",kABPersonPhoneMobileLabe
l, &multivalueIdentifier
);
if (!didAdd) {}
didAdd = ABMultiValueAddValueAndL
abel(multi, @"(555) 555-2345",kABPersonPhoneMainLabel, &multivalueIdentifier);
if (!didAdd) {}
ABRecordRef aRecord = ABPersonCreate();
didSet = ABRecordSetValue(aRecord, kABPersonPhoneProperty, multi, &anError);
if (!didSet) {}
CFRelease(multi);
CFStringRef phoneNumber, phoneNumberLabel;
multi = ABRecordCopyValue (aRecord, kABPersonPhoneProperty );
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
phoneNumberLabel
= ABMultiValueCopyLabelAtI
ndex
(multi, i);
phoneNumber
= ABMultiValueCopyValueAtI
ndex
(multi, i);
CFRelease(phoneNumberLabel);
CFRelease(phoneNumber);
}
CFRelease(aRecord);
CFRelease(multi);
4)街道地址:
街道地址使用一个multivalue的字典来表示。上面所有讨论的multivalue仍然适用于street address。这个属性的每个值都有一个label,例如home或work,并且每个值都是一个street address--使用字典来存储。在这个值内的字典包含keys表示接到地址的不同部分。
下面是例子:
ABMutableMultiValueRef address =ABMultiValueCreateMutabl
e(kABDictionaryPropertyTyp
e);
// Set up keys and values for the dictionary.
CFStringRef keys[5];
CFStringRef values[5];
keys[0] = kABPersonAddressStreetKe
y;
keys[1] = kABPersonAddressCityKey;
keys[2] = kABPersonAddressStateKey
;
keys[3] = kABPersonAddressZIPKey;
keys[4] = kABPersonAddressCountryK
ey;
values[0] = CFSTR("1234 Laurel Street");
values[1] = CFSTR("Atlanta");
values[2] = CFSTR("GA");
values[3] = CFSTR("30303");
values[4] = CFSTR("USA");
CFDictionaryRef aDict = CFDictionaryCreate(
kCFAllocatorDefault,
(void *)keys,
(void *)values,
5,
&kCFCopyStringDictionaryK
eyCallBacks,
&kCFTypeDictionaryValueCa
llBacks
);
// Add the street address to the multivalue.
ABMultiValueIdentifier identifier;
bool didAdd;
didAdd = ABMultiValueAddValueAndL
abel(address, aDict, kABHomeLabel, &identifier);
if (!didAdd) {}
CFRelease(aDict);
CFRelease(address);
三、用户交互:提示和显示数据
Address Book UI框架提供了3个view Controllers和一个navigation Controller来处理一般地的Address Book数据库和联系人信息。通过使用这个controller而不是你自己创建它们,你可以显著地减少你需要写的代码,并提供一致的用户体验。
1、有什么可用的?
Address Book UI框架提供了4个controllers:
1)ABPeoplePickerNavigation Controller提示用户选择一个联系人记录。
2)ABPersonViewController显示一个联系人记录并可选地允许用户修改。
3)ABNewPersonViewControlle r提示用户创建一个新的联系人
4)ABUnknownPersonViewContr oller提示用户完善一个联系人资料,可选地允许用户将其添加到adress book。
如图所示:
要使用这个Controller,你需要为他们设置一个代理。你一般不需要子类化它们;要修改他们的行为一般是通过代理来完成。
2、提示用户选择一个联系人记录:
使用ABPeoplePickerNavigation
Controller
步骤:
1)创建和初始化ABPeoplePickerNavigation
Controller类的实例。
2)设置代理,遵循ABpeoplePickerNavigation
ControllerDelegate协议。
3)可选地,设置你想显示的displayedProperties属性(该属性为一个array)。相关的常量被定义为integer;使用NSNumber包装。
4)presentModalViewControll
er:animated:来显示它。
例子:
ABPeoplePickerNavigation
Controller *picker = [[ABPeoplePickerNavigation
Controller alloc] init];
picker.peoplePickerDelegate = self;
[self presentModalViewControll
er:picker animated:YES];
代理函数:
1)如果用户点击了取消,调用peoplePickerNavigationCo
ntrollerDidCancel:代理方法
2)如果用户选择了一个person,调用peoplePickerNavigationCo
ntroller:shouldContinueAfterSelec
tingPerson:代理函数来决定people picker是否继续。要提示用户选择选中联系人的某个属性,那就返回YES,否则返回NO。
3)如果用户选择了一个person的某个属性,调用peoplePickerNavigationCo
ntroller:shouldContinueAfterSelec
tingPerson:property:identifier:代理方法来决定people picker是否继续。要为选中的属性执行默认的动作(例如拨打电话,开始一个新邮件等等),返回YES。否则返回NO
3、显示和编辑联系人记录:
使用ABPersonViewController类来显示联系人。
步骤:
1)创建并初始化它的实例。
2)设置代理,必须遵循ABPersonViewControllerDe
legate协议。要允许用户编辑联系人,设置allowsEditing属性为YES。
3)设置displayedPerson属性为你想要显示的person record。
4)可选地,设置displayedProperties属性为你想要显示的属性(该属性为一个array)。
5)使用pushViewController:animted:来显示它。 Person View Controller必须使用navigation Controller来显示。
例子:
ABPersonViewController *view = [[ABPersonViewController alloc] init];
view.personViewDelegate = self;
view.displayedPerson = person; // Assume person is already defined.
[self.navigationController pushViewController:view animated:YES];
如果用户轻击了属性,调用personViewController:shouldPerformDefaultActi
onForPerson:property:identifier:代理方法来决定是否执行默认行为。要执行默认行为,返回YES,否则返回NO。
4、提示用户创建一个新的联系人记录:
使用ABNewPersonViewControlle
r
步骤:
1)创建并实例化该类。
2)设置代理,必须遵循ABNewPersonViewControlle
rDelegate协议。要填充某些字段,设置displayedPerson属性。要将新联系人放到一个特定的组中,设置 parentGroup。
3)创建并实例化一个新的Navigation contrller,并设置其root view controller为new-person view controller。
4)使用presentModalViewControll
er:animated:来显示navigation controller。
例子:
ABNewPersonViewControlle
r *view = [[ABNewPersonViewControlle
r alloc] init];
view.newPersonViewDelegate = self;
UINavigationController *newNavigationController = [[UINavigationController alloc] initWithRootViewControll
er:view];
[self presentModalViewControll
er:newNavigationController animated:YES];
当用户轻击保存或取消按钮时,调用newPersonViewController:didCompleteWithNewPerson
:代理方法。如果用户单击的保存,那么新联系人记录是第一个被添加到address book的记录;如果用户单击的取消,那么person为NULL。
5、提示用户从已存在的数据创建一个新的联系人记录
使用ABUnknownPersonViewContr
oller
步骤:
1)创建并实例化。
2)创建一个新的person记录并populate要显示的属性
3)设置displayedPerson属性为这个新的person记录
4)设置代理,必须遵循ABUnknownPersonViewContr
ollerDelegate协议
5)要允许用户添加unknown-person view controller显示的信息到一个已经存在的联系人或创建一个新的联系人,那么就设置allowsAddingToAddressBoo
k为YES。
6)使用pushViewContrlller:animted:来显示Unknown-person view controller。
例子:
ABUnknownPersonViewContr
oller *view = [[ABUnknownPersonViewContr
oller alloc] init];
view.unknownPersonViewDelegat
e = self;
view.displayedPerson = person; // Assume person is already defined.
view.allowsAddingToAddressBoo
k = YES;
[self.navigationController pushViewController:view animated:YES];
当用户完成创建一个新的联系人或添加属性到一个已经存在的联系人时,调用unknownPersonViewControl
ler:didResolveToPerson:代理函数,并返回person record。如果用户取消了,person为NULL。
四、直接交互:代码访问数据库
使用代码修改联系人信息,这一般需要用户确认。尤其是组,因为手机上没有界面让用户管理组,用户没办法回退你做的更改。
1、使用Record Identifiers:
地址簿数据库里的每个记录都有一个identifier。这个identifier总是和同一个record相关,除非记录被删除了或者MobileMe同步数据被重置了。Record Identifier可以在多个线程中安全地传递。但是在不同设备之间不保证。
要保持一个长时间的引用到某个特定的记录,推荐方法是在使用identifier之外,还另外存储其first name和last name。当你通过ID来查找一个联系人时,比较联系人的name和你存储的name。如果他们不匹配,使用存储的name来查找联系人,然后为这个联系人存储新的id。
要获得一个记录的identifier,使用函数ABRecordGetRecordID函数。要通过identifier来查找一个person,使用ABAddressBookGetPersonWi
thRecordID。要通过identifier查找一个组,使用函数ABAddressBookGetGroupWit
hRecordID。要通过name来查找record,
使用函数ABAddressBookCopyPeopleW
ithName。
2、使用Person Records:
你可以添加和移除联系人到/从地址簿,使用函数ABAddressBookAddRecord和ABAddressBookRemoveRecor
d。
有两个方法来从地址簿中查找联系人:BAddressBookGetPersonWit
hRecordID和ABAddressBookCopyPeopleW
ithName。要实现其它类型的搜索,使用函数ABAddressBookCopyArrayOf
AllPeople,然后使用NSArray的filteredArrayUsingPredic
ate:方法来过滤结果。
要排序联系人,使用函数CFArraySortValues与函数ABPersonComparePeopleByN
ames作为比较器和一个类型为ABPersonSortOrdering的上下文(一般使用ABPersonGetSortOrdering来获得用户期望的排序顺序)。
下面是排序的例子:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people = ABAddressBookCopyArrayOf
AllPeople(addressBook);
CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy
(
kCFAllocatorDefault,
CFArrayGetCount(people),
people
);
CFArraySortValues(
peopleMutable,
CFRangeMake(0, CFArrayGetCount(peopleMutable)),
(CFComparatorFunction) ABPersonComparePeopleByN
ame,
(void*) ABPersonGetSortOrdering()
);
CFRelease(addressBook);
CFRelease(people);
CFRelease(peopleMutable);
3、使用Group Records:
使用ABAddressBookGetGroupWit
hRecordID来查找一个特定的组。你还可以检索所有的组,使用函数:ABAddressBookCopyArrayOf
AllGroups, 要检索有多少个组,使用函数ABAddressBookGetGroupCou
nt。
你可以使用代码来修改一个组的成员。要添加成员,使用函数ABGroupAddMemeber;要移除成员,使用ABGroupRemoveMember。在添加联系人到一个组之前,这个联系人首先需要存在于地址簿中。如果你需要添加一个新的联系人到一个组并且同时添加到数据库,你必须首先将其添加到数据库,保存数据库,然后再将其添加到组。
1、
#import <AddressBookUI/AddressBookUI.h>
ViewController遵循< ABPeoplePickerNavigation
相关方法:
- (IBAction)showPicker:(id)sender
{
}
相关代理方法:
- (void) peoplePickerNavigationCo
{ //这个方法在用户取消选择时调用
}
- (BOOL) peoplePickerNavigationCo
}
- (BOOL) peoplePickerNavigationCo
{ //这个方法在用户选择了一个person的属性时调用
}
ABRecordRef类型的对象属性:
- (void)displayPerson:( ABRecordRef )person
{//显示一个person
}
二、Building Blocks:Working with Records and Properties
你需要理解4种类型的对象才能完全与Address Book数据库完全交互:address books,records,single-value properties,和mulitivalue properties。这章讨论数据是如何存储在这些对象中,并描述了与这些对象交互的 函数。
1、Address Books:
Address Books对象允许你与Address Book数据库交互。要使用Address Book,声明一个ABAddressBookRef实例,并用ABAddressBookCreate 函数设置其值。
重要提示:ABAddressBookRef 实例不能在多个线程中共用。每个线程必须有其自己的实例。
在你创建了address book reference之后,你的应用就可以从其中读取数据,并且更改并保存它。要保存更改,使用ABAddressBookSave :函数;要放弃更改,使用ABAddressBookRevert 。要检查是否有未保存的更改,使用ABAddressBookHasUnsavedC
下面是例子:
ABAddressBookRef addressBook ;
bool wantToSaveChanges = YES;
bool didSave;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
if (ABAddressBookHasUnsavedC
}
CFRelease(addressBook);
在另一个应用或另一个线程对Address Book Database做出更改时,你的应用程序可以请求接收一个通知。一般地,如果你正在显示已经存在的联系人并且你想更新UI来反应联系人的更改,那么你应该注册一个通知。
使用函数ABAddressBookRegisterExt
当你接收到一个change callback,你需要做两件事:如果你没有未保存的更改,你的代码应该简单地revert(恢复)你的address book来得到最新的数据。如果你有未保存的更改,你可能不想恢复并丢失这些更改。如果你应该保存,Address Book Database会尽力merge你的更改和外部的更改。但是,如果更改不能合并或保存失败,你应该准备好其它的动作。
2、Records:
在Address Book 数据库里,信息被存储到records里,使用ABRecordRef表示。每个record表示一个联系人或一个组。函数ABRecordGetRecordType 返回kABPersonType 表示这是联系人,返回kABGroupType表示这是一个组。熟悉Mac OS的Address Book技术的开发者应该注意没有单独的类来区分records的类型;person对象和group对象都是一个类的实例。
重要提示:Record对象不能在线程间安全传递。取而代之的,你应该传递相应的record identifer。
record可以在Address Book 数据库之外存在。这使得他们在存储联系人信息时很有用。
在一个Record内部,数据被存储为属性的集合。group和person对象的可用属性是不一样的,但是 访问他们的函数一样。函数ABRecordCopyValue 和ABRecordSetValue 用来读取和设置属性。ABRecordRemoveValue 用来移除属性。
3、Person Records:
Person Record有单值属性和多值属性。例如first name和last nam e是单值属性,street address和phone number是多值属性。属性名可以通过kABPersonPhoneProperty这样的常量来获得,例如:
NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProper
NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty );
4、Group Records:
Group Records只有一个属性,kABGroupNameProperty,表示组的名称。要获得属于这个组的所有联系人,使用ABGroupCopyArrayOfAllMem
5、属性:
1)单值属性:
ABRecordRef aRecord = ABPersonCreate();
CFErrorRef anError = NULL;
bool didSet;
didSet = ABRecordSetValue(aRecord, kABPersonFirstNameProper
if (!didSet) {}
didSet = ABRecordSetValue (aRecord, kABPersonLastNamePropert
if (!didSet) {}
CFStringRef firstName, lastName;
firstName = ABRecordCopyValue(aRecord, kABPersonFirstNameProper
lastName
CFRelease(aRecord);
CFRelease(firstName);
CFRelease(lastName);
2)多值属性:
多值属性由一组值组成,每个值拥有一个text label和一个 相关的identifier。相同的label可以有多个value,但是identifier是唯一的。
例如,下图显示了一个电话号码属性。这里,一个联系人有多个电话号码 ,每个电话号码都有一个text label ,例如home或work,并且有一个identifier。注意,这个例子有2个家庭电话,他们有相同的label, 但是有不 同的identifier。
一个多值属性的每个单独的值可以通过index或identifier 来获取。使用函数ABMultiValueGetIndexForI
要保持多值属性中的某一个特定值,就存储它的identifier。因为index会变,但identifier不会变,除非设备变了。
ABMultiValueCopyLabelAtI
ABMultiValueCopyArrayOfA
3)可变多值属性:
Multivalue对象是不可变的,要更改它你需要创建一个可变的拷贝 ,通过函数ABMultiValueCreateMutabl
下面的函数用来更改可变MultiValue的属性:
ABMultiValueAddValueAndL
ABMultiValueReplaceValue
ABmultiValueRemoveValueA
下面是例子:
ABMutableMultiValueRef multi = ABMultiValueCreateMutabl
CFErrorRef anError = NULL;
ABMultiValueIdentifier multivalueIdentifier;
bool didAdd, didSet;
// Here, multivalueIdentifier is just for illustration purposes; it isn't
// used later in the listing.
// reference the newly-added value.
didAdd = ABMultiValueAddValueAndL
if (!didAdd) {}
didAdd = ABMultiValueAddValueAndL
if (!didAdd) {}
ABRecordRef aRecord = ABPersonCreate();
didSet = ABRecordSetValue(aRecord, kABPersonPhoneProperty, multi, &anError);
if (!didSet) {}
CFRelease(multi);
CFStringRef phoneNumber, phoneNumberLabel;
multi = ABRecordCopyValue (aRecord, kABPersonPhoneProperty );
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
}
CFRelease(aRecord);
CFRelease(multi);
4)街道地址:
街道地址使用一个multivalue的字典来表示。上面所有讨论的multivalue仍然适用于street address。这个属性的每个值都有一个label,例如home或work,并且每个值都是一个street address--使用字典来存储。在这个值内的字典包含keys表示接到地址的不同部分。
下面是例子:
ABMutableMultiValueRef address =ABMultiValueCreateMutabl
// Set up keys and values for the dictionary.
CFStringRef keys[5];
CFStringRef values[5];
keys[0] = kABPersonAddressStreetKe
keys[1] = kABPersonAddressCityKey;
keys[2] = kABPersonAddressStateKey
keys[3] = kABPersonAddressZIPKey;
keys[4] = kABPersonAddressCountryK
values[0] = CFSTR("1234 Laurel Street");
values[1] = CFSTR("Atlanta");
values[2] = CFSTR("GA");
values[3] = CFSTR("30303");
values[4] = CFSTR("USA");
CFDictionaryRef aDict = CFDictionaryCreate(
);
// Add the street address to the multivalue.
ABMultiValueIdentifier identifier;
bool didAdd;
didAdd = ABMultiValueAddValueAndL
if (!didAdd) {}
CFRelease(aDict);
CFRelease(address);
三、用户交互:提示和显示数据
Address Book UI框架提供了3个view Controllers和一个navigation Controller来处理一般地的Address Book数据库和联系人信息。通过使用这个controller而不是你自己创建它们,你可以显著地减少你需要写的代码,并提供一致的用户体验。
1、有什么可用的?
Address Book UI框架提供了4个controllers:
1)ABPeoplePickerNavigation
2)ABPersonViewController显示一个联系人记录并可选地允许用户修改。
3)ABNewPersonViewControlle
4)ABUnknownPersonViewContr
如图所示:
要使用这个Controller,你需要为他们设置一个代理。你一般不需要子类化它们;要修改他们的行为一般是通过代理来完成。
2、提示用户选择一个联系人记录:
使用ABPeoplePickerNavigation
步骤:
1)创建和初始化ABPeoplePickerNavigation
2)设置代理,遵循ABpeoplePickerNavigation
3)可选地,设置你想显示的displayedProperties属性(该属性为一个array)。相关的常量被定义为integer;使用NSNumber包装。
4)presentModalViewControll
例子:
ABPeoplePickerNavigation
picker.peoplePickerDelegate = self;
[self presentModalViewControll
代理函数:
1)如果用户点击了取消,调用peoplePickerNavigationCo
2)如果用户选择了一个person,调用peoplePickerNavigationCo
3)如果用户选择了一个person的某个属性,调用peoplePickerNavigationCo
3、显示和编辑联系人记录:
使用ABPersonViewController类来显示联系人。
步骤:
1)创建并初始化它的实例。
2)设置代理,必须遵循ABPersonViewControllerDe
3)设置displayedPerson属性为你想要显示的person record。
4)可选地,设置displayedProperties属性为你想要显示的属性(该属性为一个array)。
5)使用pushViewController:animted:来显示它。 Person View Controller必须使用navigation Controller来显示。
例子:
ABPersonViewController *view = [[ABPersonViewController alloc] init];
view.personViewDelegate = self;
view.displayedPerson = person; // Assume person is already defined.
[self.navigationController pushViewController:view animated:YES];
如果用户轻击了属性,调用personViewController:shouldPerformDefaultActi
4、提示用户创建一个新的联系人记录:
使用ABNewPersonViewControlle
步骤:
1)创建并实例化该类。
2)设置代理,必须遵循ABNewPersonViewControlle
3)创建并实例化一个新的Navigation contrller,并设置其root view controller为new-person view controller。
4)使用presentModalViewControll
例子:
ABNewPersonViewControlle
view.newPersonViewDelegate = self;
UINavigationController *newNavigationController = [[UINavigationController alloc] initWithRootViewControll
[self presentModalViewControll
当用户轻击保存或取消按钮时,调用newPersonViewController:didCompleteWithNewPerson
5、提示用户从已存在的数据创建一个新的联系人记录
使用ABUnknownPersonViewContr
步骤:
1)创建并实例化。
2)创建一个新的person记录并populate要显示的属性
3)设置displayedPerson属性为这个新的person记录
4)设置代理,必须遵循ABUnknownPersonViewContr
5)要允许用户添加unknown-person view controller显示的信息到一个已经存在的联系人或创建一个新的联系人,那么就设置allowsAddingToAddressBoo
6)使用pushViewContrlller:animted:来显示Unknown-person view controller。
例子:
ABUnknownPersonViewContr
view.unknownPersonViewDelegat
view.displayedPerson = person; // Assume person is already defined.
view.allowsAddingToAddressBoo
[self.navigationController pushViewController:view animated:YES];
当用户完成创建一个新的联系人或添加属性到一个已经存在的联系人时,调用unknownPersonViewControl
四、直接交互:代码访问数据库
使用代码修改联系人信息,这一般需要用户确认。尤其是组,因为手机上没有界面让用户管理组,用户没办法回退你做的更改。
1、使用Record Identifiers:
地址簿数据库里的每个记录都有一个identifier。这个identifier总是和同一个record相关,除非记录被删除了或者MobileMe同步数据被重置了。Record Identifier可以在多个线程中安全地传递。但是在不同设备之间不保证。
要保持一个长时间的引用到某个特定的记录,推荐方法是在使用identifier之外,还另外存储其first name和last name。当你通过ID来查找一个联系人时,比较联系人的name和你存储的name。如果他们不匹配,使用存储的name来查找联系人,然后为这个联系人存储新的id。
要获得一个记录的identifier,使用函数ABRecordGetRecordID函数。要通过identifier来查找一个person,使用ABAddressBookGetPersonWi
2、使用Person Records:
你可以添加和移除联系人到/从地址簿,使用函数ABAddressBookAddRecord和ABAddressBookRemoveRecor
有两个方法来从地址簿中查找联系人:BAddressBookGetPersonWit
要排序联系人,使用函数CFArraySortValues与函数ABPersonComparePeopleByN
下面是排序的例子:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people = ABAddressBookCopyArrayOf
CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy
CFArraySortValues(
);
CFRelease(addressBook);
CFRelease(people);
CFRelease(peopleMutable);
3、使用Group Records:
使用ABAddressBookGetGroupWit
你可以使用代码来修改一个组的成员。要添加成员,使用函数ABGroupAddMemeber;要移除成员,使用ABGroupRemoveMember。在添加联系人到一个组之前,这个联系人首先需要存在于地址簿中。如果你需要添加一个新的联系人到一个组并且同时添加到数据库,你必须首先将其添加到数据库,保存数据库,然后再将其添加到组。