I am trying to retrieve all the contacts from the AddressBook and store the following details in a Mutable array.
The properties are
#property (nonatomic, assign) ABAddressBookRef addressBook;
#property (nonatomic, strong) NSMutableArray *contactList;
#property (nonatomic, strong) IBOutlet UITableView *contactsTableView;
Method to retrieve all contacts
- (void)getAllContacts {
//line moved inside For loop as per Amar's answer.
//NSMutableDictionary *personModel = [[NSMutableDictionary alloc]initWithCapacity:0];
self.addressBook = ABAddressBookCreateWithOptions(NULL, NULL); //iOS 6 and above
CFArrayRef cList = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(self.addressBook, NULL, kABPersonSortByFirstName);
CFIndex nPeople = ABAddressBookGetPersonCount(self.addressBook);
for (int i=0; i<nPeople; i++) {
//Moving this line here per Amar's answer below. The code works perfectly now.
NSMutableDictionary *personModel = [[NSMutableDictionary alloc]initWithCapacity:0];
ABRecordRef personRef = CFArrayGetValueAtIndex(cList, i); // Person will have name, phone number, address, email id and contact image
//Get the name
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(personRef, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(personRef, kABPersonLastNameProperty));
NSString *name = nil;
if(firstName!=nil && lastName!=nil) { //both names are available
name = [NSString stringWithFormat:#"%# %#",firstName,lastName];
} else if(firstName!=nil && lastName==nil) { //last name not available
name = [NSString stringWithFormat:#"%#",firstName];
} else if(firstName==nil && lastName!=nil) { //first name not available
name = [NSString stringWithFormat:#"%#",lastName];
} else {
name = #"Unnamed Contact"; //both names not available
}
//Get the phone numbers
ABMultiValueRef phoneRef = ABRecordCopyValue(personRef, kABPersonPhoneProperty);
NSMutableArray *phoneNumbers = [NSMutableArray new];
CFIndex ctr = ABMultiValueGetCount(phoneRef);
if(ctr!=0) {
NSString *phoneNumber = nil;
for (CFIndex i=0; i<ctr; i++) {
phoneNumber = (__bridge NSString *) ABMultiValueCopyValueAtIndex(phoneRef, i);
[phoneNumbers addObject:phoneNumber];
}
} else {
[phoneNumbers addObject:#"Phone not available"];
}
//Get the contact address
ABMultiValueRef addrRef = ABRecordCopyValue(personRef, kABPersonAddressProperty);
NSMutableArray *addresses = [NSMutableArray new];
ctr = ABMultiValueGetCount(addrRef);
if(ABMultiValueGetCount(addrRef)!=0) {
for(CFIndex i=0; i<ABMultiValueGetCount(addrRef); i++) {
CFDictionaryRef addr = ABMultiValueCopyValueAtIndex(addrRef, i);
NSString *street = (__bridge NSString *)CFDictionaryGetValue(addr, kABPersonAddressStreetKey);
NSString *city = (__bridge NSString *)CFDictionaryGetValue(addr, kABPersonAddressCityKey);
NSString *state = (__bridge NSString *)CFDictionaryGetValue(addr, kABPersonAddressStateKey);
NSString *zip = (__bridge NSString *)CFDictionaryGetValue(addr, kABPersonAddressZIPKey);
NSString *address = [NSString stringWithFormat:#"%#, %#, %# %#",street,city,state,zip];
[addresses addObject:address];
}
} else {
[addresses addObject:#"Address not available"];
}
//Get the email address
ABMultiValueRef emailRef = ABRecordCopyValue(personRef, kABPersonEmailProperty);
NSMutableArray *emailAddresses = [NSMutableArray new];
ctr = ABMultiValueGetCount(emailRef);
if(ctr!=0) {
for(CFIndex i=0; i<ctr; i++) {
NSString *eId = (__bridge NSString*)ABMultiValueCopyValueAtIndex(emailRef, i);
[emailAddresses addObject:eId];
}
} else {
[emailAddresses addObject:#"EmailID not available"];
}
//Get the contact image
UIImage *image = nil;
if(ABPersonHasImageData(personRef)) image = (__bridge UIImage *)(ABPersonCopyImageDataWithFormat(personRef, kABPersonImageFormatThumbnail));
//Append the values to a dictionary
[personModel setValue:name forKey:#"cName"];
[personModel setValue:phoneNumbers forKey:#"cPhone"];
[personModel setValue:addresses forKey:#"cAddresses"];
[personModel setValue:emailAddresses forKey:#"cEmailID"];
[personModel setValue:image forKey:#"cImage"];
[self.contactList addObject: personModel];
}
}
In tableView's datasource method cellForRowAtIndexPath
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ContactsCell forIndexPath:indexPath];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:16];
cell.textLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.font = [UIFont systemFontOfSize:14.0];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSDictionary *model = [self.contactList objectAtIndex:indexPath.row];
NSLog(#"Name:%#",[model valueForKey:#"cName"]);
cell.textLabel.text =[model valueForKey:#"cName"];
return cell;
}
There are four contacts in my address book. However, my tableView always returns the last contact's name (which is "Unnamed Contact" as it has no first/last name).
Unnamed Contact
Unnamed Contact
Unnamed Contact
Unnamed Contact
Any idea why?
That's because this line
NSMutableDictionary *personModel = [[NSMutableDictionary alloc]initWithCapacity:0];
is outside the for-loop. You are creating the dictionary just once before iterating your contact list and modifying the same dictionary. Hence it will always store the last contact info.
Instead, move the above line of code inside the for loop, it will create a new dictionary for storing each contact in your list.
Hope that helps!
every time you store you data in dictionary with same KEY 'cName' "
[personModel setValue:name forKey:#"cName"];" Thats why every time
value was overwrite with same key and last record was store in
dictionary thats why the issue was raised, you need to store your data
with different key or get data directly from array rather then
dictionary
Related
I have written this code
contactlistvc.h
#import <UIKit/UIKit.h>
#interface ContactListVc : UIViewController<UITableViewDataSource,UITableViewDelegate>
{
UITableView *contactTable;
NSMutableArray *tableData;
}
#property (strong, nonatomic) IBOutlet UITableView *contactTable;
#property (nonatomic, strong) NSMutableArray *tableData;
contactlistvc.m
#import "ContactListVc.h"
#import <AddressBook/AddressBook.h>
#import "Person.h"
#interface ContactListVc ()
#end
#implementation ContactListVc
#synthesize tableData,contactTable;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationBar.backgroundColor = [UIColor blueColor];
tableData = [[NSMutableArray alloc]init];
contactTable = [[UITableView alloc]init];
contactTable.dataSource = self;
contactTable.delegate = self;
[self getPersonOutOfAddressBook];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
Person *person = [self.tableData objectAtIndex:indexPath.row];
cell.textLabel.text = person.fullName;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)getPersonOutOfAddressBook
{
//1
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (addressBook != nil) {
NSLog(#"Succesful.");
NSLog(#"tabledata %#",tableData);
//2
NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
//3
NSUInteger i = 0; for (i = 0; i < [allContacts count]; i++)
{
Person *person = [[Person alloc] init];
ABRecordRef contactPerson = (__bridge ABRecordRef)allContacts[i];
//4
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(contactPerson,
kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(contactPerson, kABPersonLastNameProperty);
NSString *fullName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
person.firstName = firstName; person.lastName = lastName;
person.fullName = fullName;
//email
//5
ABMultiValueRef emails = ABRecordCopyValue(contactPerson, kABPersonEmailProperty);
//6
NSUInteger j = 0;
for (j = 0; j < ABMultiValueGetCount(emails); j++) {
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, j);
if (j == 0) {
person.homeEmail = email;
NSLog(#"person.homeEmail = %# ", person.homeEmail);
}
else if (j==1) person.workEmail = email;
}
//7
[self.tableData addObject:person];
}
//8
CFRelease(addressBook);
} else {
//9
NSLog(#"Error reading Address Book");
}
}
But i am not getting the contact list. only successfull is coming on console window. I am having 3 tab bar on one tab of contact i want to show the contact list of phone in tableview. Plz help me , thanks.
You need to first get permission to access the native DB...
- (void)requestPermissionForContactsAccessAndFetch
{
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status != kABAuthorizationStatusAuthorized && status != kABAuthorizationStatusNotDetermined) {
// tell user to enable contacts in privacy settings
NSLog(#"You previously denied access: You must enable access to contacts in settings");
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) {
[self getContactsFromAddressBook:addressBook];
} else {
// tell user to enable contacts in privacy settings
NSLog(#"You just denied access: You must enable access to contacts in settings");
}
CFRelease(addressBook);
});
}
Then you can get all contacts in an array...
- (NSMutableArray*)getContactsFromAddressBook:(ABAddressBookRef)addressBook
{
NSArray *allData = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
NSInteger contactCount = [allData count];
for (int i = 0; i < contactCount; i++) {
ABRecordRef person = CFArrayGetValueAtIndex((__bridge CFArrayRef)allData, i);
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
if (firstName) {
dictionary[#"firstName"] = firstName;
}
if (lastName) {
dictionary[#"lastName"] = lastName;
}
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount(phones);
if (phoneNumberCount > 0) {
NSString *phone = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, 0));
dictionary[#"phone"] = phone;
}
// or if you wanted to iterate through all of them, you could do something like this...
// for (int j = 0; j < phoneNumberCount; j++) {
// NSString *phone = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, j));
// }
if (phones) {
CFRelease(phones);
}
[arrOfContacts addObject:dictionary];
}
}
Below is what I am using to retrieve the contacts list from the device. I want it to be displayed alphabetically but using other examples seen on stack overflow I have been unable to get it to work.
The code below is from a tutorial, what do I need to do to it to sort according to alphabetical order?
- (void)getPersonOutOfAddressBook
{
//1
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (addressBook != nil) {
NSLog(#"Succesful.");
//2
NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
//3
NSUInteger i = 0; for (i = 0; i < [allContacts count]; i++)
{
Person *person = [[Person alloc] init];
ABRecordRef contactPerson = (__bridge ABRecordRef)allContacts[i];
//4
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(contactPerson,
kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(contactPerson, kABPersonLastNameProperty);
NSString *fullName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
person.firstName = firstName; person.lastName = lastName;
person.fullName = fullName;
//email
//5
ABMultiValueRef emails = ABRecordCopyValue(contactPerson, kABPersonEmailProperty);
//6
NSUInteger j = 0;
for (j = 0; j < ABMultiValueGetCount(emails); j++) {
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, j);
if (j == 0) {
person.homeEmail = email;
NSLog(#"person.homeEmail = %# ", person.homeEmail);
}
else if (j==1) person.workEmail = email;
}
//7
[self.tableData addObject:person];
}
//8
CFRelease(addressBook);
} else {
//9
NSLog(#"Error reading Address Book");
}
}
This is my UITableView code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
Person *person = [self.tableData objectAtIndex:indexPath.row];
cell.textLabel.text = person.fullName;
return cell;
}
I have tried below
[self.tableData sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
I have also tried NSSortDescriptor but I don't have a Key to sort by.
You'll need to sort the array of Person objects. Once you have finished adding them all to the array you can sort on the fullName using the following code:
[self.tableData sortUsingComparator:^NSComparisonResult(Person *p1, Person *p2) {
return [p1.fullName compare:p2.fullName];
}];
Alternative
You may want to implement a compare: method on the Person object and perform the comparison there, this will keep sorting logic nicely encapsulated and ensure that anything else that uses Person objects can easily perform sorts without duplicating the code shown above.
#implementation Person
// Mostly likely this implementation will contain more code, not shown for brevity
- (NSComparisonResult)compareByFullName:(Person *)otherPerson {
return [self.fullName compare:otherPerson.fullName];
}
#end
Then you can sort the array with:
[self.tableData sortUsingSelector:#selector(compareByFullName:)];
You need to implement and provide a method to sort a Person record as a selector for the sortUsingSelector method invocation.
I managed to solve it like this.
//keys with fetching properties NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactEmailAddressesKey]; CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
//Order contacts by Surname. request.sortOrder = CNContactSortOrderFamilyName;
--OR YOU CAN--
//Order contacts by Name. request.sortOrder = CNContactSortOrderGivenName;
I'm creating a UITableView with a list of the users contacts. I've successfully imported the list of contacts and am storing them within an array as a dictionary containing each contact's forename, last name & ID reference. I'm trying to implement the UITableView's indexed list function.
I'm hitting problems when trying to partition the array into the different sections in the table's index UILocalizedIndexedCollation. Specifically by the selector. I want to be able to choose whether to sort the names by the forename or surname.
- (void)getContacts
{
// Do any additional setup after loading the view, typically from a nib.
_addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
ABAddressBookRequestAccessWithCompletion(_addressBook, ^(bool granted, CFErrorRef error) {
NSLog(#"GRANTED");
});
NSArray *rawContactData = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(_addressBook);
NSMutableArray *newContactList = [[NSMutableArray alloc] init];
for (int i = 0; i < [rawContactData count]; i++) {
ABRecordRef contact = (__bridge ABRecordRef)rawContactData[i];
NSDictionary *contactData = #{ #"name" : (__bridge_transfer NSString *)ABRecordCopyValue(contact, kABPersonFirstNameProperty),
#"surname" : (__bridge_transfer NSString *)ABRecordCopyValue(contact, kABPersonLastNameProperty),
#"recordID" : [NSNumber numberWithInt:ABRecordGetRecordID(contact)]};
[newContactList addObject:contactData];
}
_tableData = [NSMutableArray arrayWithArray:[self partitionObjects:newContactList collationStringSelector:#selector(name)]];
}
-(NSArray *)partitionObjects:(NSArray *)array collationStringSelector:(SEL)selector
{
UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation];
NSInteger sectionCount = [[collation sectionTitles] count]; //section count is take from sectionTitles and not sectionIndexTitles
NSMutableArray *unsortedSections = [NSMutableArray arrayWithCapacity:sectionCount];
//create an array to hold the data for each section
for(int i = 0; i < sectionCount; i++)
{
[unsortedSections addObject:[NSMutableArray array]];
}
//put each object into a section
for (NSMutableDictionary *object in array) {
NSInteger index = [collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
//sort each section
for (NSMutableArray *section in unsortedSections)
{
[sections addObject:[collation sortedArrayFromArray:section collationStringSelector:selector]];
}
return sections;
}
Selector is sent to the Object which you are sorting in array. In your case your object is type Dictionary which does not implement selector "name" or surname etc. You should create a simple class instead of using dictionary. and just declare properties to your liking
#interface Contact : NSObject
#property (strong,nonatomic) NSString *fname;
#property (strong,nonatomic) NSString *lname;
#property (strong,nonatomic) NSNumber *rerordId;
#end
You can then use this object instead of dictionary you are using.
Contact *contact= [[Contact alloc]init];
contact.fname = (__bridge_transfer NSString *)
ABRecordCopyValue(contact, kABPersonFirstNameProperty);
contact.lname = (__bridge_transfer NSString *)
ABRecordCopyValue(contact, kABPersonLastNameProperty);
contact.recrordId = [NSNumber numberWithInt:ABRecordGetRecordID(contact)].stringValue;
[newContactList addObject:contact];
Then you can use any name in or attribute selector. Just like in your example you will write the function call sorting with fname for example like this
_tableData = [NSMutableArray arrayWithArray:
[self partitionObjects:newContactList
collationStringSelector:#selector(fname)]];
I have an application in which I have a UITextField where when I enter a character in UITextField it searches for any matches in my address book and if any match is found it display name and emailaddress of the respective person on a UITableView.
My problem is I am not able to search properly using predicate on my address book. When I enter any character it always displays the last record whether it matches my predicate or not.
This is my code. This is my textfieldchange method:
-(void)textFieldDidChange:(UITextField *)txtFld {
[self fetchAddressBook];
NSString *dictionaryKey = contact.name;
NSString *predicateString = contact.email;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#", dictionaryKey, predicateString];
listFiles = [NSMutableArray arrayWithArray:[self.namearray
filteredArrayUsingPredicate:predicate]];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:contact.name ascending:YES] ;
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [listFiles sortedArrayUsingDescriptors:sortDescriptors];
if ([sortedArray count]>0)
{
tblView.hidden=FALSE;
txtSendAmount.hidden=TRUE;
txtSendMessage.hidden=TRUE;
[tblView reloadData];
}
else if ([sortedArray count]==0)
{
tblView.hidden=TRUE;
txtSendAmount.hidden=FALSE;
txtSendMessage.hidden=FALSE;
}
}
this is the code where i am fetching my email and name of person from address book and saving in an array
-(void)fetchAddressBook
{
CFErrorRef error = nil;
ABAddressBookRef allPeople = ABAddressBookCreateWithOptions(NULL,&error);
CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(allPeople);
CFIndex numberOfContacts = ABAddressBookGetPersonCount(allPeople);
NSMutableArray *testarray = [[NSMutableArray alloc] init];
NSMutableDictionary *addressdict = [[NSMutableDictionary alloc] init];
for(int i = 0; i < numberOfContacts; i++){
name = #"";
NSString* phone = #"";
email = #"";
contact = [[MContact alloc] init];
ABRecordRef aPerson = CFArrayGetValueAtIndex(allContacts, i);
ABMultiValueRef fnameProperty = ABRecordCopyValue(aPerson, kABPersonFirstNameProperty);
ABMultiValueRef lnameProperty = ABRecordCopyValue(aPerson, kABPersonLastNameProperty);
ABMultiValueRef phoneProperty = ABRecordCopyValue(aPerson, kABPersonPhoneProperty);
ABMultiValueRef emailProperty = ABRecordCopyValue(aPerson, kABPersonEmailProperty);
NSArray *emailArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(emailProperty);
NSArray *phoneArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneProperty);
if (fnameProperty != nil) {
contact.name = [NSString stringWithFormat:#"%#", fnameProperty];
}
if (lnameProperty != nil) {
contact.name = [contact.name stringByAppendingString:[NSString stringWithFormat:#" %#", lnameProperty]];
}
if ([phoneArray count] > 0) {
if ([phoneArray count] > 1) {
for (int i = 0; i < [phoneArray count]; i++) {
phone = [phone stringByAppendingString:[NSString stringWithFormat:#"%#\n", [phoneArray objectAtIndex:i]]];
}
}else {
phone = [NSString stringWithFormat:#"%#", [phoneArray objectAtIndex:0]];
}
}
if ([emailArray count] > 0) {
if ([emailArray count] > 1) {
for (int i = 0; i < [emailArray count]; i++) {
contact.email = [contact.email stringByAppendingString:[NSString stringWithFormat:#"%#\n", [emailArray objectAtIndex:i]]];
}
}else {
contact.email = [NSString stringWithFormat:#"%#", [emailArray objectAtIndex:0]];
}
}
[self.emailnamearray addObject:contact];
self.namearray = [emailnamearray copy];
}
}
this is my cellforrowAtIndexPath method
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tblView dequeueReusableCellWithIdentifier:#"eventCell"];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"eventCell"];
}
MContact *addressdict = [listFiles objectAtIndex:indexPath.row];
cell.textLabel.text=addressdict.name;
cell.detailTextLabel.text=addressdict.email;
return cell;
}
Your bug is there:
NSString *dictionaryKey = contact.name;
NSString *predicateString = contact.email;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#", dictionaryKey, predicateString];
The key should be #"name" or #"email", not a particular contact's name. Same for the sort descriptor.
I am trying to retrieve contacts from address book on iOS.
In my NSLOG all seems ok, but when I put all contacts to tableview (Labels etc), it's showing white cell and accessory only but 3 times ( I have only 3 contacts, and count working well in this case)
#interface ViewController ()
#end
#implementation ViewController
#synthesize searchBar,contactsTableView, retrievedContacts;
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"All Contacts";
self.tableData = [[NSMutableArray alloc] init];
retrievedContacts = [[NSMutableArray alloc] init];
self.contactsTableView.dataSource = self;
self.contactsTableView.delegate = self;
[self getPersons];
[self.contactsTableView reloadData];
}
-(void)getPersons {
// [retrievedContacts removeAllObjects];
int i;
ABAddressBookRef contactBook = ABAddressBookCreate();
NSMutableArray *allData = (__bridge_transfer NSMutableArray *)(ABAddressBookCopyArrayOfAllPeople(contactBook));
CFIndex contactNum = CFArrayGetCount((__bridge CFArrayRef)(allData));
for (i = 0; i < contactNum; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex((__bridge CFMutableArrayRef)(allData), i);
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
phonesNum = ABRecordCopyValue(ref, kABPersonPhoneProperty);
[retrievedContacts addObject:(__bridge id)(firstName)];
[retrievedContacts addObject:(__bridge id)(lastName)];
[retrievedContacts addObject:(__bridge id)(phonesNum)];
NSLog(#"First name %#", firstName);
NSLog(#"Last Name %#", lastName);
NSLog(#"Phone %#", phonesNum);
}
NSLog(#"Count Contacts %li", contactNum);
//self.tableData = retrievedContacts;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [retrievedContacts count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"Cell";
abCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [tableView dequeueReusableCellWithIdentifier:cellID];
}
cell.firstNameLabel.text = [retrievedContacts objectAtIndex:indexPath.row];
cell.lastNameLabel.text = [retrievedContacts objectAtIndex:indexPath.row];
return cell;
}
And here NSLOG Output:
2013-05-28 15:50:39.260 GTCallBack[39242:c07] First name: Anton
2013-05-28 15:50:39.261 GTCallBack[39242:c07] Last Name: SAnton
2013-05-28 15:50:39.262 GTCallBack[39242:c07] Phone numbers: ABMultiValueRef 0x797e6e0 with 2 value(s)
0: _$!<Mobile>!$_ (0x797ee30) - +972 (58) 123 4567 (0x797ee50)
1: iPhone (0x7976cc0) - +972 (58) 123 4567 (0x797ee10)
2013-05-28 15:50:39.262 GTCallBack[39242:c07] Contact Image: Anton
2013-05-28 15:50:39.263 GTCallBack[39242:c07] First name: Anton
2013-05-28 15:50:39.263 GTCallBack[39242:c07] Last Name: Anton
2013-05-28 15:50:39.264 GTCallBack[39242:c07] Phone numbers: ABMultiValueRef 0x6d8c560 with 1 value(s)
0: _$!<Mobile>!$_ (0x6d8c940) - (058) 123 4567 (0x6d8c960)
2013-05-28 15:50:39.268 GTCallBack[39242:c07] Contact Image: Anton
2013-05-28 15:50:39.269 GTCallBack[39242:c07] First name: Shalom
2013-05-28 15:50:39.270 GTCallBack[39242:c07] Last Name: Shalom
2013-05-28 15:50:39.270 GTCallBack[39242:c07] Phone numbers: ABMultiValueRef 0x7c689d0 with 1 value(s)
0: _$!<Mobile>!$_ (0x7c604c0) - (058) 123 4567 (0x7c6bff0)
2013-05-28 15:50:39.271 GTCallBack[39242:c07] Contact Image: Shalom
2013-05-28 15:50:39.301 GTCallBack[39242:c07] Count Contacts 3
Maybe there is another way to fill table with contacts data?
Thanks
First you need to get alloc init for array, custom cell labels also.
You not add data correctly in array.
for (i = 0; i < contactNum; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex((__bridge CFMutableArrayRef)(allData), i);
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
phonesNum = ABRecordCopyValue(ref, kABPersonPhoneProperty);
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
[dic setObject:(__bridge id)(firstName) forKey:#"firstName"];
[dic setObject:(__bridge id)(lastName) forKey:#"lastName"];
[dic setObject:(__bridge id)(phonesNum) forKey:#"phonesNum"];
[retrievedContacts addObject:dic];
NSLog(#"First name %#", [dic objectForKey:#"firstName"]);
NSLog(#"Last Name %#", [dic objectForKey:#"lastName"]);
NSLog(#"Phone %#",[dic objectForKey:#"phonesNum"]);
}
Check if NSLog is printing working.
In cellForRow method access array in this way.
NSMutableDictionary *dic = [retrievedContacts objectAtIndex:indexPath.row];
cell.firstNameLabel.text = [dic objectForKey:#"firstName"];
cell.lastNameLabel.text = [dic objectForKey:#"lastName"];
I have finished my issue yesterday. Now all working.
Here is the code.
#import "ViewController.h"
#import "ContactDetailsViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize searchBar, contactsTableView;
- (void)viewDidLoad {
[super viewDidLoad];
contacts = [[Contacts alloc] init];
[contacts getContacts];
self.title = #"All Contacts";
self.contactsTableView.dataSource = self;
self.contactsTableView.delegate = self;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [contacts.firstNames count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"Cell";
abCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [tableView dequeueReusableCellWithIdentifier:cellID];
}
cell.firstNameLabel.text = [contacts.firstNames objectAtIndex:indexPath.row];
cell.lastNameLabel.text = [contacts.lastNames objectAtIndex:indexPath.row];
/*for (NSString *value in [retrievedContacts objectAtIndex:indexPath.row]) {
NSMutableArray *tmp = [[NSMutableArray alloc] init];
[tmp addObject:[[retrievedContacts objectAtIndex:indexPath.row] valueForKey:value]];
NSLog(#"Contact: %#", tmp);
}*/
/*NSLog(#"Name: %#", [[retrievedContacts objectAtIndex:indexPath.row] valueForKey:#"First Name"]);
NSLog(#"Familie: %#", [[retrievedContacts objectAtIndex:indexPath.row] valueForKey:#"Last Name"]);
NSLog(#"PHONE TYPE: %# • PHONE NUMBER: %#", [[[retrievedContacts objectAtIndex:indexPath.row] objectForKey:#"Phones"] valueForKey: #"Phone Label"], [[[retrievedContacts objectAtIndex:indexPath.row] objectForKey:#"Phones"] valueForKey: #"Phone Number"]);*/
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.contactsTableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"NextView"]) {
ContactDetailsViewController *nextController = [segue destinationViewController];
NSIndexPath *indexPath = [[[self contactsTableView] indexPathsForSelectedRows] objectAtIndex:0];
[nextController setPhoneTypes:[contacts.phoneTypes objectAtIndex:[indexPath row]]];
[nextController setPhoneNumbers:[contacts.phoneNumbers objectAtIndex:[indexPath row]]];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
#import "Contacts.h"
#implementation Contacts
#synthesize firstNames, lastNames, phoneTypes, phoneNumbers, photos, retrievedContacts;
-(void)getContacts {
ABAddressBookRef addressBook = ABAddressBookCreate();
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
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);
dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
if (accessGranted) {
int i;
firstNames = [[NSMutableArray alloc] init];
lastNames = [[NSMutableArray alloc] init];
phoneTypes = [[NSMutableArray alloc] init];
phoneNumbers = [[NSMutableArray alloc] init];
photos = [[NSMutableArray alloc] init];
ABAddressBookRef contactBook = ABAddressBookCreate();
NSMutableArray *allData = (__bridge_transfer NSMutableArray *)(ABAddressBookCopyArrayOfAllPeople(contactBook));
contactNum = CFArrayGetCount((__bridge CFArrayRef)(allData));
retrievedContacts = [[NSMutableArray alloc] init];
for (i = 0; i < contactNum; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex((__bridge CFMutableArrayRef)(allData), i);
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
phonesNum = ABRecordCopyValue(ref, kABPersonPhoneProperty);
ContactImg = ABRecordCopyValue(ref, kABPersonImageFormatThumbnail);
ABMutableMultiValueRef phoneNum = ABRecordCopyValue(ref, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNum );
if (!firstName) {
[firstNames addObject:#"NO NAME"];
//NSLog(#"FN %# • LN %# • CI %#", firstName, lastName, ContactImg);
} else if (!lastName) {
[lastNames addObject:#"NO LAST NAME"];
} else if (!ContactImg) {
[photos addObject:#"NOIMG.png"];
} else {
/*NSMutableArray *person = [[NSMutableArray alloc] init];
[person addObject:(__bridge id)(firstName)];
[person addObject:(__bridge id)(lastName)];
//[person addObject:(__bridge id)(phonesNum)];
[person addObject:(__bridge id)(ContactImg)];
[retrievedContacts addObject:person];*/
[firstNames addObject:(__bridge id)(firstName)];
[lastNames addObject:(__bridge id)(lastName)];
[photos addObject:(__bridge id)(ContactImg)];
NSMutableArray *tmpType = [[NSMutableArray alloc] init];
NSMutableArray *tmpNumbr = [[NSMutableArray alloc] init];
for (int k = 0; k < phoneNumberCount; k++ )
{
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNum, k );
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNum, k );
CFStringRef phoneNumberLocalizedLabel = ABAddressBookCopyLocalizedLabel( phoneNumberLabel ); // converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
NSLog(#"-----PHONE ENTRY -> %# : %#\nPERSON NUM. %i • PHONE NUM. %i", phoneNumberLocalizedLabel, phoneNumberValue, i, k );
[tmpType addObject:(__bridge id)(phoneNumberLocalizedLabel)];
[tmpNumbr addObject:(__bridge id)(phoneNumberValue)];
CFRelease(phoneNumberLocalizedLabel);
CFRelease(phoneNumberLabel);
CFRelease(phoneNumberValue);
}
[phoneTypes addObject:tmpType];
[phoneNumbers addObject:tmpNumbr];
#ifdef DEBUG
//NSLog(#"First name: %#", firstName);
//NSLog(#"Last Name: %#", lastName);
//NSLog(#"Phone numbers: %#", phonesNum);
//NSLog(#"Contact Image: %#", ContactImg);
//NSLog(#"Some Text %#", retrievedContacts); //Here everething is OK :)
#endif
}
}
}
}
#end
Hope it will save to someone a time.
Thanks to all
Try type casting like this:
cell.firstNameLabel.text = (NSString*)[retrievedContacts objectAtIndex:indexPath.row];
cell.lastNameLabel.text = (NSString*)[retrievedContacts objectAtIndex:indexPath.row];
Or you can try this before adding to array:
NSString *firstName = (NSString *)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(ref, kABPersonLastNameProperty);
I have used similar code and it worked for me.
Hope this helps.