0

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

Anton
  • 3,102
  • 2
  • 28
  • 47
  • Do NSLog in numberOfRowsInSection and print [retrievedContacts count]. tell the output – Durgaprasad May 28 '13 at 13:03
  • How do you set up your cell? check that firstNameLabel and lastNameLabel are initialised properly – Vladimir May 28 '13 at 13:04
  • 1
    In table cell do you get firstname and lastname same? Have you done alloc init to retrievedContacts array? – Durgaprasad May 28 '13 at 13:06
  • Think the problem only in those 2 lines: cell.firsnameLabel etc. when I put this one cell.firstNameLabel.text = @"Hello"; it's working well. 3 times show me Hello. – Anton May 28 '13 at 13:13
  • @Vladimir property (strong, nonatomic) IBOutlet UILabel *firstNameLabel; property (strong, nonatomic) IBOutlet UILabel *lastNameLabel; – Anton May 28 '13 at 13:19
  • @Durgaprasad when I did that, my app crashed – Anton May 28 '13 at 13:24
  • I cant see alloc init for array. then you cant add any object in that. Edit your question with alloc init. – Durgaprasad May 28 '13 at 13:25
  • @Durgaprasad I did alloc init for all custom cell objects; it crashes on cell.firstNameLabel.text with an error: -[__NSCFType isEqualToString:]: unrecognized selector sent to instance 0x6d72400 2013-05-28 16:36:42.047 GTCallBack[40547:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType isEqualToString:]: unrecognized selector sent to instance 0x6d72400' – Anton May 28 '13 at 13:38
  • @Anton. phone numbers (kABPersonPhoneProperty) is multi-value object, not an NSString. So while it is not directly problem of your question is will need to fix that as well – Vladimir May 28 '13 at 13:47
  • @Vladimir I know that, bit NSLog is going well, and Currently I'd like to show only first Name and Last Name – Anton May 28 '13 at 13:52
  • @Durgaprasad in your option nslog show the same as mine. but nothing happened. Now I know 100% the problem is in cellForRowAtIndexPath method – Anton May 28 '13 at 13:56
  • @Anton, you put each 3 values you get from contact to your array separately, so if you have 3 contacts normally you should have 9 objects in your array. Try to put breakpoint in cellForRowAtIndexPath method and print contents of array (run 'po retrievedContacts' in debug console) to see what you actually trying to display. – Vladimir May 28 '13 at 13:58
  • @Vladimir I didn't understand your question, Now I only retrieving 1 object - firstName. I see it 3 times on slog. for each contact. – Anton May 28 '13 at 14:06
  • @Durgaprasad I think I have found root of the issue: [retrievedContacts addObject:(__bridge id)(firstName)]; [retrievedContacts addObject:(__bridge id)(lastName)]; Here NSLog show me null 3 times when trying to print retrievecontacts. It not adding to array all vars. from some reason – Anton May 28 '13 at 18:13
  • I am creating an object NSMutableArray *retrievedContacts = [[NSMutableArray alloc]init]; [retrievedContacts addObject:(__bridge id)(firstName)]; [retrievedContacts addObject:(__bridge id)(lastName)]; NSLog now show me all data from contacts. but my table method can't see this variable retrievedContacts, so I created another mutable array cellData and put retrievedContacts to CellData. cell.firstNameLabel.text = [cellData objectAtIndex:indexPath.row]; // Here I am getting NULL Something wrong in this line – Anton May 28 '13 at 19:04
  • try to NSLog [retrievedContacts objectAtIndex:0]; If that gives null then (__bridge id)(lastName) may be wrong way. – Durgaprasad May 29 '13 at 04:35

3 Answers3

2

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"];
Durgaprasad
  • 1,910
  • 2
  • 25
  • 44
  • HelloI have finished my issue tesreday. – Anton May 29 '13 at 10:23
  • the problem was, that I really need to do alloc init, to create an object and there is I needed to do some logic in the code and create another mutable array and than put my array to another, because this array not global var. Anyway we did with friend the same but with dictionary. – Anton May 29 '13 at 10:44
0

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

Anton
  • 3,102
  • 2
  • 28
  • 47
-1

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.

Nameet
  • 650
  • 8
  • 20