Anton
Anton

Reputation: 3120

iOS UItableView remove object from array by index path

I have custom contact book sorted by A-Z sections. I am trying to add to an array selected contacts

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

NSMutableDictionary *contactInfo = [NSMutableDictionary new];

Cell *cell = (Cell *)[self.contTableView cellForRowAtIndexPath:indexPath];

//NSLog(@"CELL %@", cell.contact.fullname);

if (!cell.contact.contactChecked) {

    cell.contactImage.image = [UIImage imageNamed:@"cell_blue_circle.png"];
    cell.contact.contactChecked = YES;
    //NSLog(@"DID SELECT %@", cell.contact.fullname);
    NSLog(@"index checked row %d section %d", indexPath.row, indexPath.section);
    [contactInfo setValue:cell.contact.fullname forKey:@"name"];
    [contactInfo setValue:cell.contact.numbers.firstObject forKey:@"phone"];

    [self.seletedPeople insertObject:contactInfo atIndex:indexPath.row];

} else {
     NSLog(@"index unchecked row %d section %d", indexPath.row, indexPath.section);
    cell.contactImage.image = [UIImage imageNamed:@"cell_gray_circle.png"];
    cell.contact.contactChecked = NO;
    [self.seletedPeople removeObjectAtIndex:indexPath.row];
}

NSLog(@"DICT SELECTED %@", self.seletedPeople);

}

What happens, that in some cell app crashing with error

* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM insertObject:atIndex:]: index 1 beyond bounds for empty array' *** First throw call stack: (0x29c02fef 0x38150c8b 0x29b1cf8f 0xf7fe9 0x2d36e56b 0x2d41d43b 0x2d2d2a91 0x2d24d38f 0x29bc8fed 0x29bc66ab 0x29bc6ab3 0x29b13201 0x29b13013 0x313f2201 0x2d2b7a59 0x10c075 0x386dcaaf) libc++abi.dylib: terminating with uncaught exception of type NSException

UPDATE:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *cellID = @"Cell";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];

if (searchResults) {

    //NSLog(@"CELL %@", cell.contact.fullname);
    contact = [searchResults objectAtIndex:indexPath.row];
    cell.contact = contact;
    cell.firstNameLabel.text = contact.fullname;
    cell.avatar.image = contact.image;
    cell.avatar.layer.borderColor = [UIColor grayColor].CGColor;
    cell.avatar.layer.borderWidth = 0.5;
    cell.avatar.layer.cornerRadius = 25.0;
    cell.avatar.layer.masksToBounds = YES;
    cell.number.text = contact.numbers.firstObject;

} else {

    NSString *sectionTitle = [[[namesDictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]
                              objectAtIndex:indexPath.section];
    NSArray *sectionContacts = [namesDictionary objectForKey:sectionTitle];
    contact = [self getContactFromArray:[sectionContacts objectAtIndex:indexPath.row]];

    cell.firstNameLabel.text = [sectionContacts objectAtIndex:indexPath.row];

    cell.avatar.image = contact.image;
    cell.avatar.layer.borderColor = [UIColor grayColor].CGColor;
    cell.avatar.layer.borderWidth = 0.5;
    cell.avatar.layer.cornerRadius = 25.0;
    cell.avatar.layer.masksToBounds = YES;
    cell.number.text = contact.numbers.firstObject;

    cell.contact = contact;

    cell.tag = indexPath.row;
}

if (contact.contactChecked) {
    cell.contactImage.image = [UIImage imageNamed:@"cell_blue_circle.png"];
} else {
    cell.contactImage.image = [UIImage imageNamed:@"cell_gray_circle.png"];

}


return cell;

}

Upvotes: 0

Views: 1655

Answers (5)

Anton
Anton

Reputation: 3120

The solution was adding contact record id to my dictionary and search with predicate this contact id. then remove it. kudos to @jassi

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {



    NSMutableDictionary *contactInfo = [NSMutableDictionary new];

    Cell *cell = (Cell *)[tableView cellForRowAtIndexPath:indexPath];

    if (!cell.contact.contactChecked) {

        cell.contactImage.image = [UIImage imageNamed:@"cell_blue_circle.png"];
        cell.contact.contactChecked = YES;
        //NSLog(@"DID SELECT %@", cell.contact.fullname);
        NSLog(@"index checked %@ ", [indexPath description]);
        [contactInfo setValue:cell.contact.fullname forKey:@"name"];
        [contactInfo setValue:cell.contact.numbers.firstObject forKey:@"phone"];
        [contactInfo setValue:@(cell.contact.contactId) forKey:@"contactId"];


        [self.seletedPeople addObject:contactInfo];

    } else {
         NSLog(@"index unchecked %@", [indexPath description]);
        cell.contactImage.image = [UIImage imageNamed:@"cell_gray_circle.png"];
        cell.contact.contactChecked = NO;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"contactId == %d", cell.contact.contactId];
        NSArray *resultTemp = [self.seletedPeople filteredArrayUsingPredicate:predicate];

    if(resultTemp.count>0)
        [self.seletedPeople removeObject:resultTemp[0]];


    }

    NSLog(@"DICT SELECTED %@", self.seletedPeople);
}

Upvotes: 0

Jassi
Jassi

Reputation: 557

The way I use in such cases. I create a model class and load the tableview with models. Now when i select a cell or deselect a cell. I just add that model in another array. After that when i de select the already selected cell, i can get the same model from the indexpath.row and then i can use NSArray method to fetch that model in that selected array and remove it from there. To fix your issue you can use indexPath.row as another key in dictionary during selection. After that when you deselect the cell use a predicate to get the added dictionary from the array that you are using to store selected ones. Once you find it delete it from the array.

Upvotes: 2

AlexKoren
AlexKoren

Reputation: 1605

As user2320861 said, the problem is on the line where you use insertObject. I would do the following:

  1. Change self.selectedPeople to a NSMutableDictionary using the following code:

    //in your @interface
    @property (nonatomic, strong) NSMutableDictionary *selectedPeople;
    
  2. Change the code in didSelectCellAtIndexPath to:

    //Since phone numbers are unique.
    self.selectedPeople[cell.contact.numbers.firstObject] = contactInfo;
    
  3. Retrieve all of the contacts later using this code:

    for(id key in self.selectedPeople) {
        NSDictionary contactInfo = [self.selectedPeople objectForKey:key];
        //Do something with that contactInfo
    }
    

Upvotes: -1

M_Waly
M_Waly

Reputation: 241

the problem here is the coupling of model with view objects , you shouldn't inquire about a certain property from the view itself (in your case the Cell) however the contact checked should have a reflect on its model from the data source object (the one you used to feed the cellForRowAtIndexPath: , where it should be inquired from.

Otherwise the code is buggy and unstable due to that coupling since it might point to an empty object

Upvotes: 1

user2320861
user2320861

Reputation: 1431

The problem is here:

[self.seletedPeople insertObject:contactInfo atIndex:indexPath.row];

if selectedPeople is empty and the user clicks on row 2, then it's going to try to insert contactInfo into row 2 which is "beyond the bounds of an empty array". Simply use addObject: instead. You'll also need to change how you remove items from that array then (probably better to use a dictionary instead).

Upvotes: 0

Related Questions