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;
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];
}
}
I want to create program that will import contacts from adressbook and show them in tableview. I already did code to download contacts from adressbook but when I'm adding them into Array and then trying to show in TableView they don't appear when I'm starting app. Here's code:
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[self getPersonOutOfAddressBook];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.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)getPersonOutOfAddressBook
{
//1
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // We are on iOS 6
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(semaphore);
});
}
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;
[self.tableData addObject:person];
}
//8
CFRelease(addressBook);
} else {
//9
NSLog(#"Error reading Address Book");
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
When I'm using debugger it shows that variables firstname, lastname and then fullname have access to adressbook because I can see name or last name of person. But I think there is problem with adding to array because I can't see anything in this array. Could someone help me? I'm beginner with Objective - C so please forbearance :)
To use an array you need to both declare it and create it. You do this by allocating and initializing the array.
self.tableData = [[NSMutableArray alloc] init];
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 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
I'm retrieving Contact name and phone no. from the Address book in my application. I'm printing them in log and it is working fine. But when I try to show them on the table view, I'm getting the exception NSInvalidArgumentException. I have a button on the view controller, pressing which the table view should get populated with the contact names and their no.s:
- (IBAction)syncContacts:(id)sender
{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
for (int i = 0; i < ABAddressBookGetPersonCount(addressBook); i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
NSString *contact = (NSString *)CFBridgingRelease(ABRecordCopyCompositeName(ref));
// NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(ref,kABPersonPhoneProperty);
// if (ABMultiValueGetCount(phoneNumbers) > 0) {
NSString *phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
// }
NSDictionary *curContact=[NSDictionary dictionaryWithObjectsAndKeys:(NSString *)contact,#"Name",phone,#"phone",nil];
[self.phoneContacts addObject:curContact];
}
tableView.delegate = self;
tableView.dataSource = self;
[tableView reloadData];
NSLog(#"%#",self.phoneContacts);
NSLog(#"%i",[self.phoneContacts count]);
}
And the table view methods are:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.phoneContacts count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
// cell.textLabel.text = [self.phoneContacts objectAtIndex:indexPath.row];
cell = [self.phoneContacts objectAtIndex:indexPath.row];
return cell;
}
What's wrong with the table view? When the phoneContacts had only the name, it was working fine.([phoneContacts addObject:contact]). But now when I'm adding the dictionary object, it is throwing this exception.
I've made a change.
cell = [[self.phoneContacts objectAtIndex:indexPath.row] objectForKey:#"AddressBook"];
The exception doesn't come now. But nothing is getting shown on screen.
Here's the edited method:
- (IBAction)syncContacts:(id)sender
{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
for (int i = 0; i < ABAddressBookGetPersonCount(addressBook); i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
// NSNumber *contact = (NSNumber *)ABRecordCopyComposite();// (ref));
NSString *contact = (NSString *)CFBridgingRelease(ABRecordCopyCompositeName(ref));
// NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(ref,kABPersonPhoneProperty);
// if (ABMultiValueGetCount(phoneNumbers) > 0) {
NSString *phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
// }
// NSDictionary *curContact=[NSDictionary dictionaryWithObjectsAndKeys:(NSString *)contact,#"Name",phone,#"phone",nil];
contact = [contact stringByAppendingString:#" "];
contact = [contact stringByAppendingString:phone];
[self.phoneContacts addObject:contact];
}
tableView.delegate = self;
tableView.dataSource = self;
[tableView reloadData];
}
The table view remains unchanged as given in the original post. It is now working.
The commented line cell.textLabel.text = [self.phoneContacts objectAtIndex:indexPath.row]; doesn't work? Can you set breakpoint and check if the cell's textlabel have the text assigned?
Assigning the cell using
cell = [[self.phoneContacts objectAtIndex:indexPath.row] objectForKey:#"AddressBook"]
wouldn't work, unless you defined phoneContacts to be subclass of UITableViewCell.