Access contact image from address book based on name
Asked Answered
S

3

1

Err,I have been pulling my hair thinking about a way from quite a few days.I have retrieved all contacts names and placed in an array using dictionary.

What I have is a model class holding a list of names,now I want to search the location of name in contacts list,depending on which I can retrieve the required contact image.

Initially googled and found out an unanswered question not pretty much similar to my requirement,the same can be glanced here

I tried several ways,the below is one way I have implemented:

EDIT

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self loadReminders];

    ReminderClass *reminderToDisplay = [self.remindersArray objectAtIndex:indexPath.row];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];

    // Now create the cell to display the reminder data
    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifier] autorelease];
        cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
        cell.textLabel.numberOfLines = 0;
        cell.textLabel.font = [UIFont fontWithName:@"Helvetica" size:17.0];
        cell.textLabel.adjustsFontSizeToFitWidth = YES;
    }

    tableView.backgroundColor = [UIColor clearColor];

    NSDateFormatter *dateFormat = [[[NSDateFormatter alloc]init]autorelease];
    [dateFormat setDateFormat:kDateFormat];
    NSDate *reminderDate = [dateFormat dateFromString:reminderToDisplay.Date]; 
    [dateFormat setDateFormat:kMinDateFormat]; 
    NSString *dateString = [dateFormat stringFromDate:reminderDate];

    NSString *valueString = [NSString stringWithFormat:@"%@'s %@",reminderToDisplay.Name,reminderToDisplay.Event];
    NSString *onString = [NSString stringWithFormat:@" on %@",dateString];
    NSString *reminderDetailsString = [valueString stringByAppendingString:onString];

    //Get the contact image based on name index from contact list
    ABAddressBookRef addressBook = ABAddressBookCreate( );
    CFStringRef reminderName = (CFStringRef)reminderToDisplay.Name;
    CFArrayRef allPeople = ABAddressBookCopyPeopleWithName(addressBook, reminderName);
    self.contactsList =[[[NSMutableArray alloc]init]autorelease];

    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
    for ( int i = 0; i < nPeople; i++ ) 
    { 
    ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i); 
    NSString *contactFirstNamePart = (NSString *)ABRecordCopyValue(ref,kABPersonFirstNameProperty);
    NSString *contactFirstName = [[[NSString alloc] initWithString:contactFirstNamePart]autorelease];
    NSString *contactLastNamePart = (NSString *)ABRecordCopyValue(ref, kABPersonLastNameProperty);

    if (contactLastNamePart == nil)
    {
        self.contactName = contactFirstName;
    }

    else
    {
        NSString *contactLastName = [[[NSString alloc] initWithString:contactLastNamePart]autorelease];
        NSString *contactLastNameString = [NSString stringWithFormat:@" %@",contactLastName]; 
        self.contactName = [contactFirstName stringByAppendingString:contactLastNameString]; 
        CFRelease(contactLastNamePart);
    }

    NSDictionary *contactsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:self.contactName, kContactName, [NSNumber numberWithInt:i], kContactIndex, nil];
    [self.contactsList addObject:contactsDictionary];
    CFRelease(contactFirstNamePart);
}

NSDictionary *contactsDictionary = [self.contactsList objectAtIndex:indexPath.row]; 
self.contactName = [contactsDictionary objectForKey:kContactName]; 
int addressIndex = [[contactsDictionary objectForKey:kContactIndex]integerValue];

ABRecordRef recordReference = CFArrayGetValueAtIndex(allPeople, addressIndex);
if (ABPersonHasImageData(recordReference))
{
    NSData *imageData = (NSData *)ABPersonCopyImageData(recordReference);
    self.reminderImage = [UIImage imageWithData:imageData];
    CFRelease(imageData);
}

CFRelease(allPeople);
CFRelease(addressBook);

    UIImage *notificationImage = reminderImage;

    if (notificationImage != nil) 
    {
        UIImageView *imageView=[[[UIImageView alloc] initWithFrame:CGRectMake(240, 3, 70, 63)]autorelease];
        imageView.backgroundColor=[UIColor clearColor];
        [imageView setImage:notificationImage];
        cell.accessoryView = imageView;
    }
    else
    {
        UIImageView *imageView=[[[UIImageView alloc] initWithFrame:CGRectMake(240, 3, 70, 63)]autorelease];
        imageView.backgroundColor=[UIColor clearColor];
        UIImage *defaultImage = [UIImage imageNamed:kDefaultImage];
        [imageView setImage:defaultImage];
        cell.accessoryView = imageView;
    }
    cell.textLabel.text = reminderDetailsString;
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    return cell;
}

Bad Access Error Screen shot

enter image description here

But I was unable to accomplish the required task.Can any one please guide me.

Thanks all in advance :)

Sagamore answered 28/2, 2013 at 15:10 Comment(8)
I dont understand how you iterate over contactsList using this for (reminderToDisplay.Name in contactsList)? What is reminderToDisplay.Name here?Inheritor
@Inheritor Actually reminderToDisplay.Name is a model class object that holds all names saved by the user,so I am checking whether the name exists in contacts list because the user might save few custom names as well.So I would want to know where the name is present in contact list,say index location.Depending on that I can get contact imageSagamore
Please check comparing using NSString isEqualToString instead of self.contactName == reminderToDisplay.Name. Also, pls NSLog ur reminderToDisplay.Name inside for loopInheritor
@Inheritor Yeah implemented what you have suggested and to my surprise I found out that reminderToDisplay.Name is holding addressIndex(kIndex) as well as fullName(kFullName) values which were the keys I used for storing retrieved contacts in dictionary i.e. contactsDictionary!!Sagamore
But reminderToDisplay.Name is intended to hold a reminder's name!!, ReminderClass *reminderToDisplay = [self.remindersArray objectAtIndex:indexPath.row];,and using reminderToDisplay.Name,reminderToDisplay.Date etc. I am populating my table view cell's with all reminder details.Wonder how the value(s) of reminderToDisplay.Name changed when logged inside for loop!!Sagamore
When I remove the statement:"for(reminderToDisplay.Name in contactList)",I am getting proper values for reminderToDisplay.Name,but even then I was unable to retrieve the proper images :(Sagamore
@Inheritor Waiting for your response,please help meSagamore
Could u please post the updated code?Inheritor
I
1

I am sharing the sample code snippet I used in one of my recent app. I have modified to fit it ur requirements and also please note that I have edited this in notepad and may have some typo errors.(Currently I dnt have mac to test it..:P) Basic idea is to fill the datasource in viewDidLoad method and use that dataSource to update the tableView. Hope this will be an input to solve your problem.

viewDidLoad

contactsToBeAdded=[[NSMutableArray alloc] init];
ABAddressBookRef addressbook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressbook);
CFIndex numPeople = ABAddressBookGetPersonCount(addressbook);
bool hasPhoneNumber = false;
for (int i=0; i < numPeople; i++) {
    hasPhoneNumber = false;
    ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
    ABMutableMultiValueRef phonelist = ABRecordCopyValue(person, kABPersonPhoneProperty);
    CFIndex numPhones = ABMultiValueGetCount(phonelist);


    if(numPhones > 0){
        hasPhoneNumber = true;

    }
    if(hasPhoneNumber){
        NSString *firstName=(NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
        NSString *lastName=(NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);

        CFTypeRef ABphone = ABMultiValueCopyValueAtIndex(phonelist, 0);
        NSString *personPhone = (NSString *)ABphone;

        NSMutableDictionary *dictToAdd = [[[NSMutableDictionary alloc]init]autorelease];
        if(firstName != nil && firstName != NULL){
            [dictToAdd setObject:firstName forKey:@"firstName"];
            CFRelease(firstName);
        }
        else{
            [dictToAdd setObject:@"" forKey:@"firstName"];
        }
        if(lastName != nil && lastName != NULL){
            [dictToAdd setObject:lastName forKey:@"lastName"];
            CFRelease(lastName);
        }
        else{
            [dictToAdd setObject:@"" forKey:@"lastName"];
        }

        if(personPhone != nil && personPhone != NULL){
            [dictToAdd setObject:personPhone forKey:@"mobile"];
            CFRelease(ABphone);
        }
        else{
            [dictToAdd setObject:@"" forKey:@"mobile"];
        }

        //Get the first name and last name added to dict and combine it to full name
        NSString *firstName = [dictToAdd objectForKey:@"firstName"];
        NSString *lastName = [dictToAdd objectForKey:@"lastName"];
        NSString *fullName = [firstName stringByAppendingString:lastName]; 

        //Now check whether the full name is same as your reminderToDisplay.Name
        if(reminderToDisplay.Name isEqualToString:fullName )
        {
            CFDataRef imageData = ABPersonCopyImageData(person);
            UIImage *image = [UIImage imageWithData:(NSData *)imageData];
            if(image != nil && image != NULL){
                [dictToAdd setObject:image forKey:@"image"];
                CFRelease(imageData);
            }
            else{
                [dictToAdd setObject:[UIImage imageNamed:TEMP_IMG] forKey:@"image"];
            }
        }

        [contactsToBeAdded addObject:dictToAdd];
    }

    CFRelease(phonelist);
}
CFRelease(allPeople);
CFRelease(addressbook);

[self.tableView reloadData];

numberOfRowsInSection

return contactsToBeAdded.count;

cellForRowAtIndexPath

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil)
{
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];

}

NSDictionary *contactToAdd;
//This way you can get the data added in viewDidLoad method
contactToAdd = [contactsToBeAdded objectAtIndex:indexPath.row];

NSString *fName = (NSString *)[contactToAdd objectForKey:@"firstName"];
NSString *lName = (NSString *)[contactToAdd objectForKey:@"lastName"];
UIImage *contactImg = (UIImage*)[contactToAdd objectForKey:@"image"];
Inheritor answered 6/3, 2013 at 4:30 Comment(4)
Thank you so much for the answer,but yet again experiment was a failure :( ,actually I have placed break point,what I observed was the condition: if(reminderToDisplay.Name isEqualToString:fullName) failedSagamore
check whether you are getting correct reminderToDisplay.Name and fullName.NSLog(reminderToDisplay.Name)Inheritor
Yeah,I have logged the results and found our contact names i.e. fullNames holding names with first and last name combined,without spaces,so let me include the space between them,so that I can then compare with my reminder namesSagamore
Perfect HRM,worked like a charm,kudos!! up-voted too,thanks once again for the concern and answer,TC :)Sagamore
A
0

when you use 'ABAddressBookCopyArrayOfAllPeople' you get an array of persons in the addressbook. I believe they are type of ABPerson.

You can now loop over them list like you are. For each one record call 'ABPersonCopyImageData' and that will give you the image data as a CFDataRef.

And remember CFDataRef is a tool free bridge to NSData.

Addis answered 28/2, 2013 at 15:25 Comment(3)
Thank you for the answer,but here the concern is not only regarding accessing the image of each person's! But I would want to know where the names I am holding exists in contacts list.So that based on index I can access those contact imagesSagamore
My apologies, I just don't understand the question then.Addis
Actually I am retrieving contacts in iphone using address book framework(let's say i have A,B,C,D,E etc. contacts).I have a list of names,let's say B,D,E,A,H,N etc. now for instance consider 'B',the name B I hold is in index 1 of my contacts list.Now I would want to find out the same,so that I can retrieve the B's contact image,hope you got it now :) Note:Please observe I hold names that are existing in contacts list as well as custom names entered/saved by the user!!Sagamore
I
0

Just try changing your code like this. You are adding dictionary items to ur contactsList, so get each dictionary and check whether it contains a key matching your reminderToDisplay.Name, if yes then do ur stuff..

for (NSDictionary* dict in contactsList)
{
   if(nil != [dict objectForKey:reminderToDisplay.Name])
   {
     //take image here
   }
}

UPDATE:

//This is the reminder's name you want to get contact image
ReminderClass *reminderToDisplay = [self.remindersArray objectAtIndex:indexPath.row];

 //Here you are adding your contacts with full name as object and kName as key, but check ur kName here
 NSDictionary *contactsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:self.contactName, kName, [NSNumber numberWithInt:i], kIndex, nil]; 
 [self.contactsList addObject:contactsDictionary];

 //I dont think this part is needed in ur code
 NSDictionary *contactsDictionary = [self.contactsList objectAtIndex:indexPath.row]; 
 self.contactName = [contactsDictionary objectForKey:kName]; 
 int addressIndex = [[contactsDictionary objectForKey:kIndex]intValue];

Now you have your contact names as a dictionary in contactsList array, iterate the array and check whether the dictionary contains your reminderToDisplay.Name as key.

for (NSDictionary* dict in contactsList)
{
    //Please note that your dict contains key as kName and object as contact name.
    if(nil != [dict objectForKey:reminderToDisplay.Name])
    {
    }
}

Also, I feel like you can do this in one single loop, like when you are iterating the addressbook itself, you can check whether the contact name is in your reminderlist and if available then extract image.

Hope this helps..all the best...

Inheritor answered 1/3, 2013 at 8:39 Comment(13)
Please find the updated code in 'EDIT' part of the post,the way you suggested didn't work!!Sagamore
for (NSDictionary* dict in contactsList) { NSLog(@"Dictionary is %@",dict); NSLog(@"Name is %@",reminderToDisplay.Name); if(nil != [dict objectForKey:reminderToDisplay.Name]) { ..... } } } dict showing contact list values i.e. name and address index,reminderInstance.Name as usual holding all reminders namesSagamore
I didn't understand what you really mean by nil!= [dict objectForKey:...] statement???,Depending on our reminderToDisplay.Name location in contact list,I would want to access the image,accessing images according to original index(contacts in addressbook) has already been achieved by me :)Sagamore
Your contactsList contains a dictionary with contact name as key and index as value..You are trying to check whether the contactsList contains reminder.Name, rt? So if it returns a value, then it means that ur contactsList contains the name u r looking for...got it? whats the result for NSLog?Inheritor
Ya..I checked ur code and it is clear that ur reminderToDisplay.Name is an NSString, then how come it be a list? Or do you want to check reminderDetailsString in ur contactsList?Inheritor
It is an NSString,not a list,but since we are populating the table view with reminders using reminderToDisplay.Name,I was whistling them as list of names,but not the list.To be specific: ReminderClass *reminderToDisplay = [self.remindersArray objectAtIndex:indexPath.row];,here reminderToDisplay holds all the array details like name,date,number etc. which we would be accessing via model class object i.e. reminderToDisplay.Name,reminderToDisplay.Date etc.Sagamore
Actually I have an idea,I want to know each and every individual name's(reminderToDisplay.Name for respective cell) index in contacts list that I have retrieved using address book and depending on that index,I can get the contact image.But I am unable to dig out the mysterious solution :(Sagamore
Sorry, I were out for weekend..;).. I have updated my answer, pls go thru it.Inheritor
That's ok,no apologies plz :) ,I have implemented what you have suggested,but it didn't work :( ,also you were mentioning //I don't think this part is needed in your code,but the fact is we need the addressindex to access the contact image,right?Sagamore
Please help me get out of this,please,struggling very badly :(Sagamore
Oops..I were bit busy out here...I wonder why you are not getting this works as this should be done with ease..I doubt there should be some silly mistake that u could have missed out..Pls try using logging effectively..I mean log every possible thing and see whether the things are coming as u expected. Also, y don't u give a try in one loop as I mentioned in the last line.Inheritor
Pardon,I haven't missed a single line of your's answer/suggestion.I have traced out a new method named ABAddressBookCopyPeopleWithName,it is meant to access the contacts(names) that are present in our reminder names list,but I am facing bad access error while retrieving first name and last name propertySagamore
Please find the updated code of mine followed by error screen shot in the updated part of postSagamore

© 2022 - 2024 — McMap. All rights reserved.