从UITableView删除项目(不删除它们)

时间:2013-09-27 20:56:22

标签: ios uitableview

我有一个相当简单的UITableView,其中包含20个项目(游戏中库存的大小)。我的自定义表格单元足够智能,可以为表示不包含项目的库存槽的单元格显示“SLOT EMPTY”文本。我有一个有效的解决方案,但想知道是否有更好的方法来处理它。

预期结果

用户的广告资源可能如下所示:

Bellybutton fuzz
Petrified weasel snout
Chocolate covered toilet seat
Coupon for a high-five from Chase
SLOT 5 EMPTY
SLOT 6 EMPTY
.
.
.
SLOT 20 EMPTY

如果用户删除马桶座圈,则列表应如下所示:

Bellybutton fuzz
Petrified weasel snout
Coupon for a high-five from Chase
SLOT 4 EMPTY
SLOT 5 EMPTY
.
.
.
SLOT 20 EMPTY

请注意,删除后列表仍然包含20个单元格,使用的单元格向上移动以占据库存的前三个插槽。

问题

我最初的尝试是使用is来使用[tableView deleteRowsAtIndexPaths:withRowAnimation:]并调整我的支持数据以反映新内容(少一个库存项目,一个额外的空插槽。)但是,这会因以下异常而崩溃:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Invalid update: invalid number of rows in section 0.  The number of rows
contained in an existing section after the update (20) must be equal to the number
of rows contained in that section before the update (20), plus or minus the number
of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or
minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

解决方案(?)

[请注意,为了清楚起见,本节中的代码大大简化了实际代码 - 问题是关于解决方案技术,而不是具体的实现细节。]

我最终想到的对我来说感觉有点像黑客,但确实产生了预期的结果。

删除项目如下所示:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        NSDictionary *item = [self itemForRowAtIndexPath:indexPath];
        if (!item) return;

        // Keep track of the deleted item count
        self.mDeletedEntries += 1;

        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
        [tableView endUpdates];

        // Remove it from the data store
        [Inventory removeInventoryItem:item];
    }
}

然后,我替换丢失的项目:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // If we have deleted some entries and need to add some new ones, schedule
    // a process to insert them.
    //
    // *This is what feels like a hack to me*
    if (self.mDeletedEntries)
    {
        [self performSelector:@selector(addEmptySlots:) withObject:tableView afterDelay:0];
    }

    // Return the current count that IOS wants (inventory size minus the deleted ones)
    return kUserMaxInventorySize - self.mDeletedEntries;
}

- (void)addEmptySlots:(UITableView *)tableView
{
    // We start adding entries into the list at the end
    int insertLocation = kUserMaxInventorySize - self.mDeletedEntries;

    [tableView beginUpdates];

    // Add the deleted entries (should only ever be 1 entry, really)    
    for (int i = 0; i < self.mDeletedEntries; ++i)
    {
        // They get added to the end of the table
        NSIndexPath *path = [NSIndexPath indexPathForRow:insertLocation + i inSection:0];
        NSArray *indexArray = [NSArray arrayWithObjects:path,nil];

        // Insert the entry. We don't need to actually add the item to our data store,
        // since empty entries will simply report "Slot empty" text.
        [tableView insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationBottom];
    }

    // These are no longer deleted
    self.mDeletedEntries = 0;

    [tableView endUpdates];
}

这有效,但这是实现这个目标的最佳方法吗?

1 个答案:

答案 0 :(得分:0)

我认为你的方法使它变得更加复杂。例如,您说您的tableview将始终有20个单元格。为什么不` - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section'只返回20?

我不确定您如何将商品存储在广告资源中。我只是编写我的示例,就好像你有一个名为库存的NSMutableArray。

我只会将20作为行数返回。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 20;
}

cellForRowAtIndexPath中检查项目是否存在您要为其创建单元格的行,或者是否应创建“SLOT EMPTY”单元格:

– tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    if ( [indexPath row] < [inventory count] ) {
        // configure a cell that represents actual inventory
        NSDictionary *item = [inventory objectAtIndex:[indexPath row]];
        ...
    } else {
        // configure a "SLOT * EMPTY" cell
        NSUInteger slotNumber = [indexPath row] - [inventory count] + 1;
        ...
    }
    ...
}

当您删除某个项目时,请将其从数组中删除,删除该行,然后在tableview底部添加一行以取代它:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        // Remove it from the data store
        [inventory removeObjectAtIndex:[indexPath row]];

        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
        // you also need to insert a row at the bottom so the number of rows is correct
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:19 inSection:0] withRowAnimation:UITableViewRowAnimationTop];
        [tableView endUpdates];
    }
}
相关问题