2013-09-27 50 views
0

我有一個相當簡單的UITableView,其中有20個項目(它們在遊戲中的庫存大小)。我的自定義表格單元格足夠智能以顯示單元格的「SLOT EMPTY」文本代表不包含商品的庫存位置。我有一個工作解決方案,但想知道是否有更好的方法來處理它。從UITableView中刪除項目(不刪除它們)

預期的結果

用戶的庫存可能是這樣的:

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]; 
} 

這個工作,但是這是實現這一目標的最佳方式是什麼?

+0

我想我只是更新表的支持數據和reloadData - 不要打擾刪除細胞。 –

+0

如何使用最初包含'SLOT%d EMPTY'的20個NSString對象的簡單NSMutableArray,然後開始用您的真實對象替換對象。刪除時,請再次將其替換爲字符串。 –

+0

@HotLicks reloadData的問題在於,您無法將項目從列表中移除。我還遇到過許多其他問題,其中包括單元格移動到表格頂部的一些極其奇怪的結果,並在已位於頂部的單元格後面運行彈跳動畫。很奇怪的東西。 – pauln

回答

0

我認爲你的方法使得它比它更復雜。例如,你說你的tableview總是有20個單元格。爲什麼不' - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section'只需返回20?

我不確定您是如何將商品存儲在您的廣告資源中的。我只是寫我的例子,就好像你有一個名爲庫存的NSMutableArray。

我只是總是返回20作爲行數。

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

cellForRowAtIndexPath檢查,以查看是否有項目存在,你正在創建一個小區,或者如果你要創建一個「空插槽」單元格的行:當你刪除一個項目

– 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]; 
    } 
} 
+0

謝謝亞歷克斯!你是完全正確的 - 我根本沒想過在更新過程中插入條目,刪除了庫存項目。在我的情況下,訣竅是在最後一個實際庫存項目(刪除後)之後立即插入新條目,而不是在列表的末尾。但是這是特定實現。 – pauln

+0

我很高興能幫上忙! – Alex