-1

I have an NSMutableArray containing sequential numbers 1,2...,n and have a UITableView that displays cells vertically ascending and in order. How would I go about deleting a row, m between 1 and n, both visually and in the data, as well as in the NSMutableArray, and then decrement by 1 the value of all cells that followed the deleted cell in the data and visually such that the firstResponder does not resign control like a reloadData method call would?


@interface TableController : UIViewController 

@property (nonatomic, retain) NSMutableArray *data;
@end


@implementation TableController
@synthesize data;

- (id)init
{
  if(self = [super init]) {
    data = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"5",nil];
  }
  return self;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  return [data count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  UITableViewCell *cell = [UITableViewCell new];
  [cell.textLabel setText:[data objectAtRow:indexPath.row]];
  return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  return 20;
}
@end

How would I remove row 3 and then make rows four and five then become 3 and 4 respectively?

rolling_codes
  • 15,174
  • 22
  • 76
  • 112
  • Post what you have tried and explain what issue you are having. – rmaddy Jun 16 '14 at 15:52
  • is that better @maddy? – rolling_codes Jun 16 '14 at 15:58
  • What are you doing here? `UITableViewCell *cell = [UITableView new];`??? – CrimsonChris Jun 16 '14 at 16:00
  • @CruimsonChris that is shorthand for [[UITableViewCell alloc] init]; – rolling_codes Jun 16 '14 at 16:00
  • 1
    @Savagewood No, it's not. You had `UITableView` there. Oh wait, you just updated it. – CrimsonChris Jun 16 '14 at 16:01
  • @CrimsonChris yes i updated good call – rolling_codes Jun 16 '14 at 16:02
  • @Savagewood you need to use [`[tableview dequeueReusableCellWithIdentifier]`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:) or [`[tableview dequeueReusableCellWithIdentifier:forIndexPath:]`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:forIndexPath:) – Benjohn Jun 16 '14 at 16:03
  • @benjohn yes yes i know, but I'm more interested in removing rows from data and visual table – rolling_codes Jun 16 '14 at 16:03
  • 2
    @Benjohn While it is a good idea to implement cell reuse. It is not _required_. – CrimsonChris Jun 16 '14 at 16:04
  • @Savagewood Slightly better. Where's your code to do a deletion? What issue are you having? – rmaddy Jun 16 '14 at 16:04
  • 1
    @CrimsonChris Oh, nice one, ta :-) – Benjohn Jun 16 '14 at 16:05
  • @maddy i have not attempted to delete because i am not sure of the best way to do it? modifying just that data? or just the visual display? and then changing the values of all following cells??? – rolling_codes Jun 16 '14 at 16:05
  • Do you want a programatic delete or a user delete of a row? If the latter, check my answer. If the former – you make the data source update as shown in @CrimsonChris's answer, then use `[tableview deleteRowsAtIndexPaths:withRowAnimation]` on the deleted row's index path as in my answer. – Benjohn Jun 16 '14 at 16:21
  • the previeous @benjohn programmatic – rolling_codes Jun 16 '14 at 16:22
  • @Savagewood To use delete: update your model, then update your tableview to reflect the new state of the model by sending `deleteRowsAsIndexPaths: …` as needed. – Benjohn Jun 16 '14 at 16:36

2 Answers2

1

Just edit your view model and then reload the table.

[data removeObjectAtIndex:2];
[tableView reloadData];

Another option is the UITableView method deleteRowsAtIndexPaths:withRowAnimation:. This approach is UI only, you must also update your view model in case the cells ever get reloaded at a later time. The advantage of this approach is that only the cells you specify get changed. Existing cells are not reloaded.

If the cell you are deleting is your first responder then you could handle this case by telling the next cell to become first responder.

CrimsonChris
  • 4,651
  • 2
  • 19
  • 30
  • reload data makes the firstResponder resign? Or am I wrong? – rolling_codes Jun 16 '14 at 16:04
  • Depends on who the first responder is. Is it one of the cells? – CrimsonChris Jun 16 '14 at 16:05
  • unfortunately so... did I pick a bad responder? XD – rolling_codes Jun 16 '14 at 16:06
  • 1
    Running `reloadData` will replace your old cells with new ones which will force them to resign first responder. This is a separate issue which could very well govern a new question. There are some answers on this subject on StackOverflow already. – CrimsonChris Jun 16 '14 at 16:08
  • If you use `reloadData`, you won't get any animations. In a real app, it's also not as performant. – Benjohn Jun 16 '14 at 16:20
  • 1
    @Benjohn It _is_ the simplest solution however. +1 on your answer for showing an example of _where_ the OP could do his deletion. – CrimsonChris Jun 16 '14 at 16:21
  • @Benjohn There is very little difference in performance if you implement cell reuse and estimated cell heights. – CrimsonChris Jun 16 '14 at 16:23
  • @CrimsonChris agree – mostly about the animation in most cases. If you've got expensive draw computations for your cell it can make sense, but then, you probably want that buffered in a UIImage or something anyway. – Benjohn Jun 16 '14 at 16:27
0

For user driven deletion, your [tableview dataSource] should implement the method tableView:commitEditingStyle:forRowAtIndexPath:.

Here's an implementation from my code…

-(void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
  if(editingStyle == UITableViewCellEditingStyleDelete)
  {
    [[STLocationsModel sharedModel] deleteLocationAtIndex: [indexPath row]];
    [tableView deleteRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationLeft];
  }
}

To allow editing, you'll also want…

-(BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
  return YES;
}

To get the table in to editing mode to allow deletions, you need to put it in to editing mode. You could place this in your viewDidLoad, or you might toggle it with a button:

[[self tableView] setEditing:YES animated:NO];

And if you also want to be able to make selections while the table is edited (again, this could go in your viewDidLoad

[[self tableView] setAllowsSelectionDuringEditing: YES];
Benjohn
  • 13,228
  • 9
  • 65
  • 127