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 :)

Community
  • 1
  • 1
Eshwar Chaitanya
  • 942
  • 2
  • 13
  • 34
  • I dont understand how you iterate over `contactsList` using this `for (reminderToDisplay.Name in contactsList)`? What is `reminderToDisplay.Name` here? – HRM Mar 01 '13 at 03:55
  • @HRM 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 image – Eshwar Chaitanya Mar 01 '13 at 05:04
  • Please check comparing using NSString `isEqualToString` instead of `self.contactName == reminderToDisplay.Name`. Also, pls NSLog ur `reminderToDisplay.Name` inside `for` loop – HRM Mar 01 '13 at 05:28
  • @HRM 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!! – Eshwar Chaitanya Mar 01 '13 at 05:43
  • 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!! – Eshwar Chaitanya Mar 01 '13 at 05:51
  • 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 :( – Eshwar Chaitanya Mar 01 '13 at 06:10
  • @HRM Waiting for your response,please help me – Eshwar Chaitanya Mar 01 '13 at 08:05
  • Could u please post the updated code? – HRM Mar 01 '13 at 08:29

3 Answers3

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"];
HRM
  • 2,097
  • 6
  • 23
  • 37
  • 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) failed – Eshwar Chaitanya Mar 06 '13 at 06:39
  • check whether you are getting correct reminderToDisplay.Name and fullName.`NSLog(reminderToDisplay.Name)` – HRM Mar 06 '13 at 06:46
  • 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 names – Eshwar Chaitanya Mar 06 '13 at 06:58
  • Perfect HRM,worked like a charm,kudos!! up-voted too,thanks once again for the concern and answer,TC :) – Eshwar Chaitanya Mar 06 '13 at 07:12
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.

John
  • 2,640
  • 1
  • 16
  • 16
  • 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 images – Eshwar Chaitanya Mar 01 '13 at 05:19
  • My apologies, I just don't understand the question then. – John Mar 01 '13 at 19:59
  • 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!! – Eshwar Chaitanya Mar 04 '13 at 12:25
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...

HRM
  • 2,097
  • 6
  • 23
  • 37
  • Please find the updated code in 'EDIT' part of the post,the way you suggested didn't work!! – Eshwar Chaitanya Mar 01 '13 at 09:25
  • 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 names – Eshwar Chaitanya Mar 01 '13 at 09:45
  • 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 :) – Eshwar Chaitanya Mar 01 '13 at 09:47
  • 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? – HRM Mar 01 '13 at 09:52
  • 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? – HRM Mar 01 '13 at 10:35
  • 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. – Eshwar Chaitanya Mar 01 '13 at 10:41
  • 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 :( – Eshwar Chaitanya Mar 01 '13 at 10:46
  • Sorry, I were out for weekend..;).. I have updated my answer, pls go thru it. – HRM Mar 04 '13 at 04:20
  • 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? – Eshwar Chaitanya Mar 04 '13 at 05:09
  • Please help me get out of this,please,struggling very badly :( – Eshwar Chaitanya Mar 05 '13 at 05:24
  • 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. – HRM Mar 05 '13 at 10:14
  • 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 property – Eshwar Chaitanya Mar 05 '13 at 13:08
  • Please find the updated code of mine followed by error screen shot in the updated part of post – Eshwar Chaitanya Mar 05 '13 at 13:09