【问题标题】:Reorder-able UITableView with Max # of Rows per Section可重新排序的 UITableView,每个部分的最大行数
【发布时间】:2010-01-10 15:31:58
【问题描述】:

我是 iPhone 开发和编程的新手,最近完成了 Stephen Kochan 的 Objective-C 2.0 编程,以及 Erica Sadun 的 iPhone Cookbook 的部分内容。仅仅阅读这个网站上回答的问题对我有很大帮助,所以我非常感谢它的所有用户。现在我正在开发我的第一个 iPhone 应用程序,并且取得了不错的进展,除了一件让我难过的事情。

我在使用 UITableView 时遇到了一些问题。基本上,我有一个表,每个部分最多需要 6 行,没有最小值(除非删除了 1 行部分的行,在这种情况下,该部分随之而来)。该表也可以由用户重新排序。当用户将一行拖入一个已经分配了最多 6 行的部分时,我希望该部分的底行向下排序以成为下一部分的顶行。

至于实现这一点,我的第一个想法是在tableView:moveRowAtIndexPath:toIndexPath: 中调用一个方法,该方法将循环遍历各个部分,确保它们都没有超过 7 行,根据需要调整数组,然后使用[myTable beginUpdates] 块删除和插入所需的行。这就是所有的样子(注意:我的数组结构是:数组(表)>数组(节)>字典(项目):

-(void) tableView: (UITableView *) tableView moveRowAtIndexPath: (NSIndexPath *) from toIndexPath: (NSIndexPath *) to
{ 
// Get the dictionary object for the icon.
NSMutableDictionary *theIcon = [[[TABLE_ARRAY_MACRO objectAtIndex: from.section] objectAtIndex: from.row] mutableCopy];

// Now remove it from the old position, and insert it in the new one.
[[TABLE_ARRAY_MACRO objectAtIndex: from.section] removeObjectAtIndex: from.row];
[[TABLE_ARRAY_MACRO objectAtIndex: to.section] insertObject: theIcon atIndex: to.row];

if ( [[TABLE_ARRAY_MACRO objectAtIndex: to.section] count] > 6 )
          [self budgeRowsAtSection: to.section];

// Now we're done with the dictionary.
[theIcon release];

if ( PM_DEBUG_MODE )
    NSLog(@"Pet moved!");
}



-(void) budgeRowsAtSection: (NSUInteger) section
{
  if ( PM_DEBUG_MODE )
   NSLog(@"Budging rows...");

  // Set up an array to hold the index paths of the cells to move.
  NSMutableArray *budgeFrom = [[NSMutableArray alloc] init];
  NSMutableArray *budgeTo = [[NSMutableArray alloc] init];

  // Start at the current section, and enumerate down to the nearest page with < 6 items.
  int i = section;

 while ( i < [TABLE_ARRAY_MACRO count] ) {

   if ( PM_DEBUG_MODE )
       NSLog(@"Attempting to budge rows in section %i!", i);

   if ( [[TABLE_ARRAY_MACRO objectAtIndex: i] count] > 6 ) {

   // Grab the last object, and move it to the beginning of the next array.
   NSMutableDictionary *lastIcon = [[[PET_ICON_DATA objectAtIndex: i] lastObject] mutableCopy];

   [[TABLE_ARRAY_MACRO objectAtIndex: i] removeLastObject];
   [[TABLE_ARRAY_MACRO objectAtIndex: (i + 1)] insertObject: lastIcon atIndex: 0];

   // Create an index path, and reflect the changes in the table.
   [budgeFrom addObject: [NSIndexPath indexPathForRow: 6 inSection: i]];
   [budgeTo addObject: [NSIndexPath indexPathForRow: 0 inSection: (i + 1)]];

   // Now we're done with the icon.
   [lastIcon release];

 }

 if ( PM_DEBUG_MODE )
      NSLog(@"Rows budged for section %i!", i);

 ++i;

}

  if ( PM_DEBUG_MODE )
    NSLog(@"From cells: %@\nTo cells: %@", budgeFrom, budgeTo);

  if ( PM_DEBUG_MODE )
    NSLog(@"Data budged! Updating table...");

  [editTable beginUpdates];
  [editTable deleteRowsAtIndexPaths: budgeFrom withRowAnimation: UITableViewRowAnimationBottom];
  [editTable insertRowsAtIndexPaths: budgeTo withRowAnimation: UITableViewRowAnimationTop];
  [editTable endUpdates];

  [budgeFrom release];
  [budgeTo release];

  if ( PM_DEBUG_MODE )
   NSLog(@"Row budge done!");
}

问题是当我运行它时,它总是抛出异常;它给了我Invalid update: number of rows in section after update must be equal to number of rows before update, + or - the number inserted or deleted (etc.)Attempted to create two animations for cell,这取决于我正在尝试的调整。至于这些调整是什么,我也尝试过使用reloadSections:withRowAnimation:,当然还有一个简单的[editTable reloadData]。我尝试在相关的 TableView 委托/数据源方法中调用此方法,包括 targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:,以及 Apple 指南中提到的 TableViews 中提到的有点神秘的 willMoveToRowAtIndexPath:fromIndexPath: 方法,但在其他地方不存在。

我在 Google、此网站和 Apple 的文档中搜索了所有关于解决方案的线索,但无济于事。

那么,简单地说,解决这个问题的最佳方法是什么?我忽略了一些明显的事情吗?还是我的实现概念从一开始就存在根本缺陷?

提前感谢您的帮助!任何见解将不胜感激。

-- 德鲁·胡德

更新:根据 Jordan 对他的回答的评论中的建议,我已经验证了对数据源的实际编辑是否正确。我现在在执行表编辑块时始终收到错误Attempt to create two animations for cell(通过常识和断点验证的时间)。所以我在编辑块中做错了。当前的代码正是如上所示。想法?

【问题讨论】:

    标签: iphone objective-c cocoa-touch uitableview


    【解决方案1】:

    [editTable beginUpdates]; [编辑表 deleteRowsAtIndexPaths:budgetFrom withRowAnimation: UITableViewRowAnimationBottom];
    [editTable insertRowsAtIndexPaths: 预算与行动画: UITableViewRowAnimationTop];
    [editTable endUpdates];

    我相信您需要先更新 DataSource,然后再实际删除要从中删除的任何部分中的 Row。所以在这段代码中,在你执行删除之前,从 Table_Array_Macro 中删除行(我认为这是你的数据所在的位置)。

    【讨论】:

    • 感谢您的回复。是的,我做到了——上面写着: [[TABLE_ARRAY_MACRO objectAtIndex: i] removeLastObject]; [[TABLE_ARRAY_MACRO objectAtIndex: (i + 1)] insertObject: lastIcon atIndex: 0];。澄清一下,我的数据源是一个数组数组(每个部分一个数组),在这些数组中是包含表格单元格实际信息的字典。
    • 尝试添加一个 NSLog 来统计之前和之后的记录数。我很确定那里有不匹配的地方。这就是错误所传达的内容。
    • 我听从了您的建议,我的阵列正在根据需要进行更改。我确保计数和内容都正确对应。一切都检查出来。我现在得到的唯一错误是“尝试为单元格创建两个动画”的事情,所以看来我的问题出现在我的编辑块中。 :-/
    【解决方案2】:

    所以,我终于解决了这个问题,并认为为了后代我会在这里发布我所做的事情。真的很简单:我只是将表中行的实际插入和删除移到了一个单独的方法中,然后我在延迟后调用了该方法。从一开始就很清楚,Jordan 帮助我确认,问题出在对表本身执行更新时,而不是在实际更改数据的过程中。所以这里是成功的代码:

    -(void) performBudges
    {
    if ( PM_DEBUG_MODE )
        NSLog(@"Performing budge animations...");
    
    [editTable beginUpdates];
    [editTable deleteRowsAtIndexPaths: budgeFrom withRowAnimation: UITableViewRowAnimationRight];
    [editTable insertRowsAtIndexPaths: budgeTo withRowAnimation: UITableViewRowAnimationRight];
    [editTable endUpdates];
    
    [editTable performSelector: @selector(reloadData) withObject: nil afterDelay: 0.5];
    
    [reloadedSections release];
    
    [budgeFrom release];
    [budgeTo release];
    
    if ( PM_DEBUG_MODE )
        NSLog(@"Budges completed!");
    } 
    

    我所要做的就是将这个 sn-p 添加到我的 moveRowAtIndexPath: 方法中:

    if ( [[PET_ICON_DATA objectAtIndex: to.section] count] > 6 ) {
    
        [self budgeRowsAtSection: to.section];
        [self performSelector: @selector(performBudges) withObject: nil afterDelay: 1.0];
    
    }
    

    因此,我希望这对将来可能遇到此问题的任何人有所帮助。感谢乔丹和所有看过这个问题的人。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-27
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多