0

我有一个相当简单的 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 个单元格,已使用的单元格向上移动以占据库存的前三个位置。

问题

我最初的尝试是使用[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];
}

这行得通,但这是实现这一目标的最佳方法吗?

4

1 回答 1

0

我认为你的方法使这比它必须的更复杂。例如,您说您的表格视图将始终恰好有 20 个单元格。为什么 `- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section' 不简单地返回 20?

我不确定您是如何将这些物品存储在库存中的。我只是要编写我的示例,就好像您有一个名为 inventory 的 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];
    }
}
于 2013-09-27T21:41:46.810 回答