可重新排序的UITableView,每行最大行数

时间:2010-01-10 15:31:59

标签: iphone objective-c cocoa-touch uitableview

我是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:,以及TableViews上的Apple指南中提到的有点神秘的willMoveToRowAtIndexPath:fromIndexPath:方法,但是不是 - 存在于其他地方。

我搜遍了谷歌,这个网站以及Apple的文档以寻找任何解决方案,但无济于事。

所以,简单地说一下,问题的最佳方法是什么?我有什么明显的东西可以忽略吗?或者我的实施概念从一开始就存在根本性的缺陷?

提前感谢您的帮助!任何见解都会非常感激。

- Drew R. Hood

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

2 个答案:

答案 0 :(得分:2)

  

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

我相信你需要更新DataSource才能在你删除它的任何部分中实际删除Row。因此,在此代码中,在执行删除之前,请从Table_Array_Macro中删除该行(我认为这是您的数据所在的位置)。

答案 1 :(得分:0)

所以,我终于解决了这个问题,并且认为我会为了后代而发布我在这里所做的事情。它非常简单,实际上:我只是将表中实际插入和删除的行移到了一个单独的方法,然后我在延迟后调用它。从一开始就很清楚,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!");
} 

我需要做的就是将此代码段添加到我的moveRowAtIndexPath:方法中:

if ( [[PET_ICON_DATA objectAtIndex: to.section] count] > 6 ) {

    [self budgeRowsAtSection: to.section];
    [self performSelector: @selector(performBudges) withObject: nil afterDelay: 1.0];

}

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