I want to get a list of all contacts of an iPhone.
I checked Address Book
reference, I may missed something but I didn't see it provides a method to get a list of contacts.
I want to get a list of all contacts of an iPhone.
I checked Address Book
reference, I may missed something but I didn't see it provides a method to get a list of contacts.
Perhaps ABPerson
function ABAddressBookCopyArrayOfAllPeople might do?
ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
...
}
ABAddressBookCreate()
has been deprecated (starting in iOS 6) in favour of ABAddressBookCreateWithOptions(NULL, error)
. –
Insubstantial autoreleasepool{}
) –
Tindal In my original answer, at the end of this answer, I show how to retrieve contacts in iOS versions prior to 9.0 in a manner that addresses some of the problems entailed by other answers here.
But, if only supporting iOS 9 and later, one should use the Contacts
framework, avoiding some of the annoying bridging issues entailed when using the older AddressBook
framework.
So, in iOS 9, you'd use the Contacts
framework:
@import Contacts;
You also need to update your Info.plist
, adding a NSContactsUsageDescription
to explain why your app requires access to contacts.
And then do something like follows:
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Access to contacts." message:@"This app requires access to contacts because ..." preferredStyle:UIAlertControllerStyleActionSheet];
[alert addAction:[UIAlertAction actionWithTitle:@"Go to Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alert animated:TRUE completion:nil];
return;
}
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
// make sure the user granted us access
if (!granted) {
dispatch_async(dispatch_get_main_queue(), ^{
// user didn't grant access;
// so, again, tell user here why app needs permissions in order to do it's job;
// this is dispatched to the main queue because this request could be running on background thread
});
return;
}
// build array of contacts
NSMutableArray *contacts = [NSMutableArray array];
NSError *fetchError;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactIdentifierKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]];
BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) {
[contacts addObject:contact];
}];
if (!success) {
NSLog(@"error = %@", fetchError);
}
// you can now do something with the list of contacts, for example, to show the names
CNContactFormatter *formatter = [[CNContactFormatter alloc] init];
for (CNContact *contact in contacts) {
NSString *string = [formatter stringFromContact:contact];
NSLog(@"contact = %@", string);
}
}];
Below is my answer applicable if supporting iOS versions prior to iOS 9.0.
--
A couple of reactions to not only your question, but also many of the answers provided here (which either fail to request permission, don't handle ABAddressBookCreateWithOptions
errors properly, or leak):
Obviously, import the AddressBook
framework:
#import <AddressBook/AddressBook.h>
or
@import AddressBook;
You must request permission for the app to access the contacts. For example:
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted) {
// if you got here, user had previously denied/revoked permission for your
// app to access the contacts and all you can do is handle this gracefully,
// perhaps telling the user that they have to go to settings to grant access
// to contacts
[[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
return;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook) {
NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error));
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error));
}
if (granted) {
// if they gave you permission, then just carry on
[self listPeopleInAddressBook:addressBook];
} else {
// however, if they didn't give you permission, handle it gracefully, for example...
dispatch_async(dispatch_get_main_queue(), ^{
// BTW, this is not on the main thread, so dispatch UI updates back to the main queue
[[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
});
}
CFRelease(addressBook);
});
Note that above, I have not used the pattern suggested by others:
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
That is not correct. As you'll see above, you want:
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
The former pattern will not capture the error correctly, whereas the latter will. If error
was not NULL
, don't forget to CFRelease
it (or transfer ownership to ARC like I did) or else you'll leak that object.
To iterate through the contacts, you want to:
- (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook
{
NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
NSInteger numberOfPeople = [allPeople count];
for (NSInteger i = 0; i < numberOfPeople; i++) {
ABRecordRef person = (__bridge ABRecordRef)allPeople[i];
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers);
for (CFIndex j = 0; j < numberOfPhoneNumbers; j++) {
NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, j));
NSLog(@" phone:%@", phoneNumber);
}
CFRelease(phoneNumbers);
NSLog(@"=============================================");
}
}
I want to draw your attention to a fairly key detail, namely the "Create Rule":
Core Foundation functions have names that indicate when you own a returned object:
Object-creation functions that have “
Create
” embedded in the name;Object-duplication functions that have “
Copy
” embedded in the name.If you own an object, it is your responsibility to relinquish ownership (using CFRelease) when you have finished with it.
This means that you bear responsibility for releasing any object returned by any Core Foundation function with Create
or Copy
in the name. You can either call CFRelease
explicitly (as I did above with addressBook
and phoneNumbers
) or, for objects that support toll-free bridging, you can transfer ownership to ARC with __bridge_transfer
or CFBridgingRelease
(as I did above with allPeople
, lastName
, firstName
, and phoneNumber
).
The static analyzer (press shift+command+B in Xcode or choose "Analyze" from the "Product" menu) can identify many situations in which you neglected to observe this "Create Rule" and failed to release the appropriate objects. So, whenever writing Core Foundation code like this, always run it through the static analyzer to make sure you don't have any obvious leaks.
Perhaps ABPerson
function ABAddressBookCopyArrayOfAllPeople might do?
ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
...
}
ABAddressBookCreate()
has been deprecated (starting in iOS 6) in favour of ABAddressBookCreateWithOptions(NULL, error)
. –
Insubstantial autoreleasepool{}
) –
Tindal Use this code to display all names + lastnames + phonenumbers (iOS 6). Works on simulator too:
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++) {
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
NSLog(@"phone:%@", phoneNumber);
}
NSLog(@"=============================================");
}
Make sure you have the proper import
#import <AddressBook/AddressBook.h>
Then you can get a CFArray object with all contacts using
CFArrayRef ABAddressBookCopyArrayOfAllPeople (ABAddressBookRef addressBook);
In iOS 6, make sure you use ABAddressBookCreateWithOptions
, which is the updated version of ABAddressBookCreate
CFErrorRef * error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++){
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
// More code here
}
Update for iOS 9.0
. Apple has deprecated AddressBook
and now they have added Contacts
framework:
Add CNContactStore
property and define it like this:
self.contactsStrore = [[CNContactStore alloc] init];
Then add these methods to read all contacts:
-(void)checkContactsAccess{
[self requestContactsAccessWithHandler:^(BOOL grandted) {
if (grandted) {
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNamePrefixKey, CNContactMiddleNameKey, CNContactPhoneNumbersKey]];
[self.contactsStrore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
NSLog(@"%@", contact.familyName);
NSLog(@"%@", contact.givenName);
NSLog(@"%@", contact.namePrefix);
NSLog(@"%@", contact.middleName);
NSLog(@"%@", contact.phoneNumbers);
NSLog(@"=============================================");
}];
}
}];
}
-(void)requestContactsAccessWithHandler:(void (^)(BOOL grandted))handler{
switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) {
case CNAuthorizationStatusAuthorized:
handler(YES);
break;
case CNAuthorizationStatusDenied:
case CNAuthorizationStatusNotDetermined:{
[self.contactsStrore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
handler(granted);
}];
break;
}
case CNAuthorizationStatusRestricted:
handler(NO);
break;
}
}
Before iOS 9.0 => Use AddressBook
framework.
You have to check for access and request access to User contacts first:
// Prompt the user for access to their Address Book data
-(void)requestAddressBookAccess
{
YourViewController * __weak weakSelf = self;
ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForAddressBook];
});
}
});
}
-(void)checkAddressBookAccess
{
switch (ABAddressBookGetAuthorizationStatus())
{
// Update our UI if the user has granted access to their Contacts
case kABAuthorizationStatusAuthorized:
[self accessGrantedForAddressBook];
break;
// Prompt the user for access to Contacts if there is no definitive answer
case kABAuthorizationStatusNotDetermined :
[self requestAddressBookAccess];
break;
// Display a message if the user has denied or restricted access to Contacts
case kABAuthorizationStatusDenied:
case kABAuthorizationStatusRestricted:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Privacy Warning"
message:@"Permission was not granted for Contacts."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
break;
default:
break;
}
}
Thanks to mahesh and wzbozon, the following code worked for me:
CFErrorRef * error = NULL;
addressBook = ABAddressBookCreateWithOptions(NULL, error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++){
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
NSMutableArray *numbers = [NSMutableArray array];
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
[numbers addObject:phoneNumber];
}
NSMutableDictionary *contact = [NSMutableDictionary dictionary];
[contact setObject:name forKey:@"name"];
[contact setObject:numbers forKey:@"numbers"];
[all_contacts addObject:contact];
}
});
}
});
Swift version:
override func viewDidLoad() {
super.viewDidLoad()
var error: Unmanaged<CFErrorRef>?
var addressBook: ABAddressBook = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue()
if ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.NotDetermined {
ABAddressBookRequestAccessWithCompletion(addressBook, {
(granted:Bool, error:CFErrorRef!) -> Void in
self.populateFrom(addressBook: addressBook)
})
}
else if ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.Authorized {
self.populateFrom(addressBook: addressBook)
}
}
func populateFrom(#addressBook:ABAddressBook){
let allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue()
let nPeople = ABAddressBookGetPersonCount(addressBook)
for index in 0..<nPeople{
let person: ABRecordRef = Unmanaged<ABRecordRef>.fromOpaque(COpaquePointer(CFArrayGetValueAtIndex(allPeople, index))).takeUnretainedValue()
let firstName: String = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String
println("\(firstName.debugDescription)")
}
}
Check out https://github.com/heardrwt/RHAddressBook (254 stars 01/2014).
Provides an ObjC wrapper for AddressBook with much simpler API.
This works for ios 7 and ios 8 , i hope its help you.............
NSMutableArray *result = [[NSMutableArray alloc] init];
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL){
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else{
accessGranted = YES;
}
if (accessGranted){
// If the app is authorized to access the first time then add the contact
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for (int i=0; i<numberOfPeople; i++){
CFStringRef phone;
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString *userName = @"NoName";
userName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
userName = [userName stringByReplacingOccurrencesOfString:@"(null)" withString:@""];
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers );
phone = nil;
for ( CFIndex ind= 0; ind<phoneNumberCount; ind++ ){
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, ind);
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, ind);
// converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
// Find the ones you want here
if (phoneNumberLabel != nil){
NSStringCompareOptions compareOptions = NSCaseInsensitiveSearch;
if(CFStringCompare(phoneNumberLabel, CFSTR("mobile"),compareOptions)){
phone = phoneNumberValue;
}
phone = phoneNumberValue;
NSStringCompareOptions compareOptionss = NSCaseInsensitiveSearch;
if(!CFStringCompare(phone, CFSTR("1-800-MY-APPLE"),compareOptionss)){
continue;
}
NSMutableArray *theKeys = [NSMutableArray arrayWithObjects:@"name", @"small_name",@"phone", @"checked", nil];
NSMutableArray *theObjects = [NSMutableArray arrayWithObjects:userName, [userName lowercaseString],phone, @"NO", nil];
NSMutableDictionary *theDict = [NSMutableDictionary dictionaryWithObjects:theObjects forKeys:theKeys];
if (![[functions formatNumber:(__bridge NSString *)(phone)] isEqualToString:[[NSUserDefaults standardUserDefaults]valueForKey:@"phoneNumber"]]){
[result addObject:theDict];
}
}
}
}
}
//sort array
NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:@"small_name"
ascending:YES]; // 1
NSArray * sortedArray = [result sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
functions
in last if
case is undefined. Also CFStringCompare
attempts to convert NSStringCompareOptions
to NSStringCompareFlags
. –
Ridglee ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
...
}
This is complete demo to fetch all contacts with table view.
import UIKit
import ContactsUI
import AddressBook
import Contacts
class ShowContactsVC: UIViewController,CNContactPickerDelegate,UITableViewDelegate,UITableViewDataSource
{
@IBOutlet weak var tableView: UITableView!
let peoplePicker = CNContactPickerViewController()
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var contacts = [CNContact]()
var option : Int = 0
var userAccessGranted : Bool = false
var dataArray : NSMutableArray?
override func viewDidLoad()
{
super.viewDidLoad()
peoplePicker.delegate = self
self.checkIfUserAccessGranted()
self.tableView.delegate = self
self.tableView.dataSource = self
navigationController!.navigationBar.barTintColor = UIColor.grayColor()
if(self.userAccessGranted)
{
self.tableView.hidden = false
fetchContacts()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if dataArray == nil {
return 0;
}
else{
return dataArray!.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("TableCell", forIndexPath: indexPath) as! ContactsTableViewCell
let data = dataArray![indexPath.row] as! Data;
cell.lblName.text = data.name
cell.imgContact.image = data.image
return cell
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
cell.backgroundColor = UIColor.cyanColor()
}
func checkIfUserAccessGranted()
{
appDelegate.requestForAccess { (accessGranted) -> Void in
if accessGranted {
self.userAccessGranted = true;
}else{
self.userAccessGranted = false;
}
}
}
func fetchContacts()
{
dataArray = NSMutableArray()
let toFetch = [CNContactGivenNameKey, CNContactImageDataKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey]
let request = CNContactFetchRequest(keysToFetch: toFetch)
do{
try appDelegate.contactStore.enumerateContactsWithFetchRequest(request) {
contact, stop in
print(contact.givenName)
print(contact.familyName)
print(contact.identifier)
var userImage : UIImage;
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
userImage = UIImage(data: imageData)!
}else{
userImage = UIImage(named: "no_contact_image")!
}
let data = Data(name: contact.givenName, image: userImage)
self.dataArray?.addObject(data)
}
} catch let err{
print(err)
}
self.tableView.reloadData()
}
func contactPickerDidCancel(picker: CNContactPickerViewController)
{
picker.dismissViewControllerAnimated(true, completion: nil)
self.navigationController?.popToRootViewControllerAnimated(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
import UIKit
class Data {
let name : String
let image : UIImage
init(name : String, image : UIImage) {
self.image = image
self.name = name
}
}
if you want to sort as a alphabetical, you can use below code.
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault,
CFArrayGetCount(allPeople),
allPeople);
CFArraySortValues(peopleMutable,
CFRangeMake(0, CFArrayGetCount(peopleMutable)),
(CFComparatorFunction) ABPersonComparePeopleByName,
kABPersonSortByFirstName);
© 2022 - 2024 — McMap. All rights reserved.