我有一个相当简单的 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];
}
这行得通,但这是实现这一目标的最佳方法吗?