2012-07-07 15 views
5

iOS 5の気の利いた行移動呼び出しを使用して、古いスタイルの削除と削除の代わりに、インサート。UITableView:using moveRowAtIndexPath:toIndexPath:andRoadRowsAtIndexPaths:withRowAnimation:一緒に壊れて表示されます。

変更にはリオーダとインプレースの両方の更新が含まれていて、両方をアニメーション化したいので、いくつかの行にはreloadRowsAtIndexPathsが必要です。

しかし! UITableViewは、更新されたセルが移動のために位置を移動した場合に、移動の存在下で行の再ロードを処理するには間違っているように見えます。以前のdelete + insert呼び出しを使用すると、同等のはずの方法で正常に動作します。

ここにいくつかのコードがあります。私は冗談をお詫びしますが、コンパイルして実行します。肉はdoMoves:メソッドにあります。以下の展覧会。

#define THISWORKS 

@implementation ScrambledList // extends UITableViewController 
{ 
    NSMutableArray *model; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    model = [NSMutableArray arrayWithObjects: 
      @"zero", 
      @"one", 
      @"two", 
      @"three", 
      @"four", 
      nil]; 
    [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle: 
#ifdef THISWORKS 
               @"\U0001F603" 
#else 
               @"\U0001F4A9" 
#endif 
                       style:UIBarButtonItemStylePlain 
                      target:self 
                      action:@selector(doMoves:)]]; 
} 

-(IBAction)doMoves:(id)sender 
{ 
    int fromrow = 4, torow = 0, changedrow = 2; // 2 = its "before" position, just like the docs say. 

    // some model changes happen... 
    [model replaceObjectAtIndex:changedrow 
        withObject:[[model objectAtIndex:changedrow] stringByAppendingString:@"\u2032"]]; 
    id tmp = [model objectAtIndex:fromrow]; 
    [model removeObjectAtIndex:fromrow]; 
    [model insertObject:tmp atIndex:torow]; 

    // then we tell the table view what they were 
    [self.tableView beginUpdates]; 
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:changedrow inSection:0]] 
         withRowAnimation:UITableViewRowAnimationRight]; // again, index for the "before" state; the tableview should figure out it really wants row 3 when the time comes 
#ifdef THISWORKS 
    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:fromrow inSection:0]] 
         withRowAnimation:UITableViewRowAnimationAutomatic]; 
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:torow inSection:0]] 
         withRowAnimation:UITableViewRowAnimationAutomatic]; 
#else // but this doesn't 
    [self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromrow inSection:0] 
         toIndexPath:[NSIndexPath indexPathForRow:torow inSection:0]]; 
#endif 
    [self.tableView endUpdates]; 
} 

#pragma mark - Table view data source boilerplate, not very interesting 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return model.count; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@""]; 
    if (cell == nil) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@""]; 
    [cell.textLabel setText:[[model objectAtIndex:indexPath.row] description]]; 
    [cell.detailTextLabel setText:[NSString stringWithFormat:@"this cell was provided for row %d", indexPath.row]]; 
    return cell; 
} 

小さなコード(小さな可変配列)を設定します。ボタンが押されると、リストの中央の要素を少し変更し、最後の要素を最初の要素に移動します。次に、テーブルビューを更新してこれらの変更を反映します。中央の行をリロードし、最後の行を削除して新しい行ゼロを挿入します。

これは機能します。実際には、cellForRowAtIndexPathにログを追加すると、2行の再読み込みを要求されますが、実際に更新を行う時間があると、tableviewは正しく3行目を要求します。フツァ!

ここで、moveRowAtIndexPathを使用する代わりに#ifdefをコメントアウトしてください。

今テーブルビュー行2を除去し、(間違った!)新鮮行を求め、最終行2位置(また、間違った!)の中に挿入します。正味の結果は、行1が2つのスロットの代わりに2つのスロットの代わりにスクロールし、画面をスクロールして強制的にリロードすることで、モデルとの同期が外れていることを示します。 moveRowAtIndexPathが、別の順序でテーブルビューのプライベートモデルを変更した場合、リロードやモデルフェッチで「古い」インデックスパスの代わりに「新しい」インデックスを使用する必要があることは理解できました。 2番目の「後」の写真では、3番目と4番目の行が逆の順序になっています。どちらのセルを読み込んでも問題ありません。

before state

after one button push, delete-insert style

after one button push, move-style

私の語彙は、カラフルなのろいのアップルが成長してきました。私は代わりに自分自身を呪っているべきですか?行は、同じ更新ブロック内の行再ロードと単純に互換性がありません(疑わしいのは、挿入と削除だけです)?バグレポートを提出する前に誰かが私を啓発することはできますか?

+0

非常に興味深い! –

+0

あなたはこれに対する解決策を見つけましたか?私はまったく同じ問題に取り組んでいます。 –

+0

私は不十分な情報で閉じられたバグレポートを提出し、ios6の下でテストする要求を出しましたが(問題は解決していないかもしれませんが、UICollectionViewにも同様の問題があります) 2つの別々のbegin/endUpdatesブロック、1つはリロード、もう1つはmove/inserts/deletesのためのものです。またはreloadRowsAtIndexPathsを完全にスキップして、適切なセルを手動で検索/再投入します。 – rgeorge

答えて

3

あなたのコードで遊ぶのにちょうど時間を費やしましたが、私は同意します。それだけで動作しないように見えます。

この全体の領域は、文書化されていませんが、実際にはmoveRowAtIndexPath:toIndexPath:とリロードメソッドを混在させることはできません。 で、行挿入と行削除の方法と混在することができます。それらを代わりに実行するようにコードを修正すれば、それらはうまくいくようです。だから、バグを提出するのではなく、改善を求めているかもしれません。いずれにせよ、私は間違いなくそれをレーダーに送ります。

+0

確認していただきありがとうございます。レーダー提出アップルがそれを解決したら、私は解決策を追加します。 – rgeorge

関連する問題