I am writing an app where I need to read the user’s address book and display a list of all his contacts. The iPhone I’m testing with has ~ 100 contacts and it takes really much time to load the contacts.
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
ABMultiValueRef phones = NULL;
ABRecordRef person = NULL;
for (int i =0; i < allContacts.count; i++) {
person = (__bridge ABRecordRef)([allContacts objectAtIndex:i]);
if (person != nil) {
phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
if (ABMultiValueGetCount(phones) == 0) {
CFErrorRef error = nil;
ABAddressBookRemoveRecord(addressBook, person, &error);
}
CFRelease(phones);
}
}
CFErrorRef saveError = nil;
ABAddressBookSave(addressBook, &saveError);
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.view.backgroundColor=[UIColor clearColor];
picker.peoplePickerDelegate = self;
picker.delegate=self;
NSArray *displayedItems =
[NSArray arrayWithObject:[NSNumber
numberWithInt:kABPersonPhoneProperty]];
picker.displayedProperties = displayedItems;
You can perform the copying in a background thread using performSelectorInBackground:withObject:, that way it won't affect the main thread and you don't have to wait in the UI.
Related
I am new in IOS Programming. In my simple app I am storing first name,last name and phone number in NSMutableArray.I have a UITextfield where I get the phone number.I wanna search first name and last name according to mobile number.I am storing firstname, lastname and phone number in different Mutable arrays so how to search firstname and lastname in stored array.
This is my code
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
_firstname = [[NSMutableArray alloc]init];
_lastname = [[NSMutableArray alloc]init];
_number = [[NSMutableArray alloc]init];
_fullname = [[NSMutableArray alloc]init];
_arrContacts = [[NSMutableArray alloc]init];
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
ABAddressBookRef addressBook = ABAddressBookCreate( );
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
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));
if (firstName != nil) {
[_firstname addObject:firstName];
}
else{
[_firstname addObject:#"Not Found"];
}
if (lastName != nil) {
[_lastname addObject:lastName];
}
else{
[_lastname addObject:#"Not Found"];
}
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
[[UIDevice currentDevice] name];
NSArray *numbers = (__bridge NSArray *)(ABMultiValueCopyValueAtIndex(phoneNumbers, 0));
if (numbers != nil) {
[_arrContacts addObject:numbers];
NSLog(#"Numbers:%#",_arrContacts);
}
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
_addressBookNum = [_addressBookNum stringByAppendingFormat: #":%#",phoneNumber];
}
}
// NSLog(#"AllNumber:%#",_addressBookNum);
}
else {
// Send an alert telling user to change privacy setting in settings app
}
CFRelease(addressBookRef);
NSLog(#"This is Name: %#",_firstname);
NSLog(#"This is LastName: %#",_lastname);
NSLog(#"Number: %#",_arrContacts);
}
Please suggest some idea to do this
Instead of saving name last name and number in different array store it in single array with dictionary. Suppose NSMutabelArray *details
create dictionary having three values name lastname and number, and add this dictoianry into array,
so it will be easy for you to further use
I'm trying to NSLog name and number from my contact in Address Book.
I succeed to log the name, but I don't succeed to solve the problem with number.
Here is my code :
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if (addressBook != NULL) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (granted) {
CFArrayRef allNames = ABAddressBookCopyArrayOfAllPeople(addressBook);
if (allNames != NULL) {
NSMutableArray *names = [NSMutableArray array];
for (int i = 0; i < CFArrayGetCount(allNames); i++) {
ABRecordRef group = CFArrayGetValueAtIndex(allNames, i);
CFStringRef name = ABRecordCopyCompositeName(group);
[names addObject:(__bridge NSString *)name];
CFRelease(name);
}
NSLog(#"names = %#", names);
CFRelease(allNames);
}
}
CFRelease(addressBook);
});
}
Maybe I have to create NSDictionnary ? I don't know how to solve it...
The phone numbers are a ABMultiValueRef:
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
if (phones != NULL) {
for (NSInteger index = 0; index < ABMultiValueGetCount(phones); index++) {
NSString *phone = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, index));
NSString *label = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phones, index)); // either kABHomeLabel or kABPersonPhoneMainLabel or ...
// do something with `phone` and `label`
}
CFRelease(phones);
}
You'll need to use ABRecordCopyValue(group, kABPersonPhoneProperty) which returns ABMultiValueRef. See https://stackoverflow.com/a/286281/171089 for more.
I am developing an app in which i have to save contact in address book, but if the the contact is already saved in contact then it should not save.
But i have no idea is it possible to check a contact whether it is exits in contact list of iPhone or not?
Any help would be appreciated.
Thanks in advance.
Solved issue
-(void)CheckContactIsExits{
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
ABRecordRef pet = ABPersonCreate();
ABRecordSetValue(pet, kABPersonFirstNameProperty, (__bridge CFStringRef)#"VoxSci Activation", nil);
for (id record in allContacts){
ABRecordRef thisContact = (__bridge ABRecordRef)record;
if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(pet), 0) == kCFCompareEqualTo){
NSLog(#"The contact already exists");
//The contact already exists!
isContactExits=YES;
}
}
}
Assuming your using Apples framework for this your user will be given the option to "create new contact" or if its already in the contacts list "add to existing contact". Therefore the user can decide if it should be added or not
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
And read all the contacts in iPhone and check the name or phone exit or not.
Check Contact is Exit or Not By Contact Number
Note : Only replace checkingPhoneNumber variable by your checking contact number
ABAddressBookRef * addressbook = ABAddressBookCreateWithOptions(Nil, Nil);
NSArray *people = (__bridge NSArray*)ABAddressBookCopyArrayOfAllPeople(addressbook);
NSMutableArray *phoneArray=[[NSMutableArray alloc] init];
for(id person in people)
{
// get person contact number
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonPhoneProperty);
NSString* mobile=#"";
NSString* mobileLabel;
for (int i=0; i < ABMultiValueGetCount(phones); i++)
{
mobileLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(phones, i);
if([mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel]) {
NSLog(#"mobile:");
} else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel]) {
NSLog(#"iphone:");
} else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhonePagerLabel]) {
NSLog(#"pager:");
}
mobile = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, i);
NSLog(#"%#", mobile);
// remove all spaces bracket from contact number
NSMutableString *newPhoneStr = [[NSMutableString alloc] init];;
int j = [mobile length];
for (int i=0; i<j; i++)
{
if ([mobile characterAtIndex:i] >=48 && [mobile characterAtIndex:i] <=59)
{
[newPhoneStr appendFormat:#"%c",[mobile characterAtIndex:i]];
}
}
//add contact into phoneArray
[phoneArray addObject:newPhoneStr];
}
}
NSLog(#"%#",phoneArray);
BOOL identicalStringFound = NO;
// remove all spaces bracket from contact number which is check
NSMutableString *newCheckingPhoneNumberStr = [[NSMutableString alloc] init];
int j = [checkingPhoneNumber length];
for (int i=0; i<j; i++)
{
if ([checkingPhoneNumber characterAtIndex:i] >=48 && [[profileDetailsDict valueForKey:#"mobile"] characterAtIndex:i] <=59)
{
[newCheckingPhoneNumberStr appendFormat:#"%c",[checkingPhoneNumber characterAtIndex:i]];
}
}
for (NSString *contact in phoneArray)
{
if ([contact isEqual:newCheckingPhoneNumberStr])
{
identicalStringFound = YES;
break;
}
}
if(identicalStringFound)
{
// checkingPhoneNumber is exit
}
else
{
// checkingPhoneNumber is not exit
}
If anybody wants to check name is saved in address book or not, then below function may be useful:
-(BOOL)isNameSaved:(NSString*)strGivenName {
BOOL isSaved = NO;
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for ( int i = 0; i < nPeople; i++ ) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef firstc = (CFStringRef)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString *first = [NSString stringWithFormat:#"%#",firstc];
if ([first isEqualToString:strGivenName]) {
isSaved = YES;
break;
}
}
return isSaved;
}
In my app I have to access the address book, so in iOS>6.0 I have to ask permission to the user.
I do this:
ABAddressBookRef addressBook = ABAddressBookCreate();
if(floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_6_0)
{
//iOS is >= 6.0
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
[self showContacts:addressBook];
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
[self showContacts:addressBook];
}
else
{
//showAccessDeniedAlert();
}
}
else
{
//iOS is < 6.0
[self showContacts:addressBook];
}
In showContacts it's all alright, but: the first time I use the app on a device, it asks me if I want to let it access the AddressBook, i press "OK" and showContactsisn't called! So I have to close the app, restart it, and it works perfectly.
This is my showContacts method:
- (void) showContacts:(ABAddressBookRef)addressBook
{
CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfContacts = ABAddressBookGetPersonCount(addressBook);
for (int ii = 0; ii < numberOfContacts; ii++)
{
ABRecordRef contactRef = CFArrayGetValueAtIndex(allContacts, ii);
ABMultiValueRef *phones = ABRecordCopyValue(contactRef, kABPersonPhoneProperty);
for(CFIndex jj = 0; jj < ABMultiValueGetCount(phones); jj++)
{
CEPerson *person = [[CEPerson alloc] init];
NSString *name = (__bridge_transfer NSString *)ABRecordCopyValue(contactRef,kABPersonFirstNameProperty);
NSString *surname = (__bridge_transfer NSString *)ABRecordCopyValue(contactRef, kABPersonLastNameProperty);
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phones, jj);
NSString *phoneNumber = (__bridge NSString *)phoneNumberRef;
person.name = name;
person.surname = surname;
person.telephone = phoneNumber;
[arrContacts addObject:person];
}
}
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"surname" ascending:YES];
[arrContacts sortUsingDescriptors:[NSArray arrayWithObject:sort]];
[self selectAllContacts];
}
How can I make it work even right after the user presses "OK"?
Thank you all.
I figured it out. I simply added
[tableView reloadData];
at the end of my showContacts method.
I am having the trouble to fetch iPhone contacts.
I have tried to fetch the contact by the following code.
It is working fine in simulator and also worked fine when the contacts are less in the contact list.
In my phone I am having 1000 Contacts. So it crashes on this device. Please guide me if you know the reason.
Here is my code.
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray* items = [NSMutableArray arrayWithCapacity:nPeople];
for (int i = 0; i < nPeople; i++)
{
NSMutableDictionary *dicContacts = [[NSMutableDictionary alloc]init];
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
NSMutableArray *phoneNumbers = [[NSMutableArray alloc] init];
ABMultiValueRef multiPhones = ABRecordCopyValue(person, kABPersonPhoneProperty);
for(CFIndex i=0;i<ABMultiValueGetCount(multiPhones);i++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(multiPhones, i);
NSString *phoneNumber = (__bridge NSString *) phoneNumberRef;
[phoneNumbers addObject:phoneNumber];
//NSLog(#"All numbers %#", phoneNumbers);
}
if ([phoneNumbers count] > 0) {
[dicContacts setValue:[phoneNumbers objectAtIndex:0] forKeyPath:#"Contact"];
}
[items addObject:dicContacts];
}
Thanks In Advance
-(void)tkPeoplePickerController:(TKPeoplePickerController*)picker didFinishPickingDataWithInfo:(NSArray*)contacts
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,error);
[contacts enumerateObjectsUsingBlock:^(id obj,NSUInteger idx, BOOL *stop)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
TKContact *contact = (TKContact*)obj;
NSNumber *personID = [NSNumber numberWithInt:contact.recordID];
ABRecordID abRecordID = (ABRecordID)[personID intValue];
ABRecordRef abPerson = ABAddressBookGetPersonWithRecordID(addressBook, abRecordID);
// Check person image
UIImage *personImage = nil;
if (abPerson != nil && ABPersonHasImageData(abPerson))
{
if ( &ABPersonCopyImageDataWithFormat != nil )
{
// iOS >= 4.1
CFDataRef contactThumbnailData = ABPersonCopyImageDataWithFormat(abPerson, kABPersonImageFormatThumbnail);
personImage = [UIImage imageWithData:(__bridge NSData*)contactThumbnailData];
CFRelease(contactThumbnailData);
ABMultiValueRef emailValues = ABRecordCopyValue(abPerson, kABPersonEmailProperty);
// This is how you extract the first item from the multivalues:
CFStringRef cfEmailAddress = ABMultiValueCopyValueAtIndex(emailValues, 0);
// This is how you convert it to an NSString.
[RSVP_ImageArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
contact.name,#"name",
contact.email,#"email",
[NSString stringWithFormat:#"%d",abRecordID],#"recodeID",
savedImagePath,#"Image",
nil]];
CFDataRef contactImageData = ABPersonCopyImageDataWithFormat(abPerson, kABPersonImageFormatOriginalSize);
CFRelease(contactImageData);
}
else
{
// iOS < 4.1
CFDataRef contactImageData = ABPersonCopyImageData(abPerson);
personImage = [[UIImage imageWithData:(__bridge NSData*)contactImageData] thumbnailImage:CGSizeMake(thumbnailSize, thumbnailSize)];
ABMultiValueRef emailValues = ABRecordCopyValue(abPerson, kABPersonEmailProperty);
// This is how you extract the first item from the multivalues:
CFStringRef cfEmailAddress = ABMultiValueCopyValueAtIndex(emailValues, 0);
// This is how you convert it to an NSString.
[RSVP_ImageArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
contact.name,#"name",
contact.email,#"email",
[NSString stringWithFormat:#"%d",abRecordID],#"recodeID",
savedImagePath,#"Image",
nil]];
CFRelease(contactImageData);
}
}
else
{
ABMultiValueRef emailValues = ABRecordCopyValue(abPerson, kABPersonEmailProperty);
// This is how you extract the first item from the multivalues:
CFStringRef cfEmailAddress = ABMultiValueCopyValueAtIndex(emailValues, 0);
// This is how you convert it to an NSString.
[mutablearray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
contact.name,#"name",
contact.email,#"email",
[NSString stringWithFormat:#"%d",abRecordID],#"recodeID",
savedImagePath,#"Image",
nil]];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
});
[pool drain];
}];
dispatch_async(dispatch_get_main_queue(), ^{
CFRelease(addressBook);
});
});
}
Use this code with it will surely help you.. for reference u can use this link https://github.com/qnibus/TKContactsMultiPicker ... :)
for(CFIndex i=0;i<ABMultiValueGetCount(multiPhones);i++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(multiPhones, i);
NSString *phoneNumber = (__bridge NSString *) phoneNumberRef;
[phoneNumbers addObject:[NSString stringWithFormat:#"%#",phoneNumber]];
//NSLog(#"All numbers %#", phoneNumbers);
}
[phoneNumbers retain];