thandasoru
thandasoru

Reputation: 1558

UITableview always loads the last object for all cells

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?

Upvotes: 1

Views: 132

Answers (2)

Dipen Chudasama
Dipen Chudasama

Reputation: 3093

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

Upvotes: 0

Amar
Amar

Reputation: 13222

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!

Upvotes: 2

Related Questions