2009/09/26

[Objective-C][iPhone sdk]tableのcellの再設定

意外にぐぐってもすぐにみつからなかったこのトピック

UITableViewControllerを使ってテーブルを表示した場合、iPhone(iPod touch)を回転させた時、teble(表)の各セルのコンテンツを再設定(再配置)をさせたい場合があります。
(レイアウトの変更ともいう。)

この場合、まず、始めに、回転させた時に、iPhoneのコンテンツを回転させるかどうかを判断するメソッド(shouldAutorotateToInterfaceOrientation)を

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}

とすればオッケーなのですが、これだけだと、単純にコンテンツが回転するだけです。

コンテンツの再描画は、iPhoneの回転が完了した時に、呼び出されるメソッド(didRotateFromInterfaceOrientation:fromInterfaceOrientation)を

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[self.tableView reloadData];
}

とすることにより、再度、自分自身のテーブルのセルを再設定しようとします。

こうした場合、当然、呼び出されるのは、- tableView:cellForRowAtIndexPathなのですが、その時に、view(contentView)にaddSubviewをしてしまうと既存のコンテンツの上にさらに再配置されたコンテンツが重なってしまい、2重に表示されることになってしまいます。

それを回避するために、元々貼り付いていたviewを取り除く必要があるのですが、下のようにプログラムした場合、iPhoneが固まってしまいました。

NSUInteger cnt;
NSUInteger i;
cnt = = [cell.contentView.subviews count];
for (i=0; i<cnt; i++) {
[[cell.contentView.subviews objectAtIndex:i] removeFromSuperview];
}

次に下のように変更しても固まりました。

NSUInteger cnt;
NSUInteger i;
cnt = = [cell.contentView.subviews count];
for (i=0; i<cnt; i++) {
[[cell.contentView.subviews objectAtIndex:i] release];
}

さらにこんな風にしても固まりました。

[cell.contentView release];

ここまでくると泣きたくなりました。

泣きたくなったので、ぐーぐる先生に聞いてみると、同様に悩んでいる人がいました。

スレッドを読んでいくと最終的にこの人は解決されたっぽく、その時のソースが書かれていました。

Solution to problem:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyIdentifier"] autorelease];
}
//
// This code below fixed the problem...
//
NSArray *subviews = [[NSArray alloc] initWithArray:cell.contentView.subviews];
for (UIView *subview in subviews) {
[subview removeFromSuperview];
}
[subviews release];
//
// Now you can continue creating the cell...
//

via:Yet Another UITableViewCell Question...

一番最初に書いたプログラムとそんな差がないのに、なぜかこれで試してみるとiPhoneが固まらずに動きました。

おそらく、subviewsのカウントをとったのが失敗なのかなと思っております。

今度からこれでいきたいと思います。

1 件のコメント:

  1. 古い記事なので既にご存知かも知れませんが、気になったので、何がいけないのか書いておきますね。(誰かの為になるかもしれませんので。)

    indexが0,1の2つのviewがsubviewとして存在していたとします。
    ループの最初では、indexが0のものが削除されますよね。 このとき、他のビューはindexが1ずつ小さくなります。そうでないとindexが連番になりませんから、これが道理です。

    ですので、次にindexが1のものを削除しようとした時には、それが存在しなくなっていて、エラーを吐く、というわけです。

    解決策としては、ここに提示されている拡張for文を用いたものが最良ですが、その他に
    for文の中身でiが大きいものから順に消すように for (i=cnt-1; 0<i; i--) とするとか、
    [cell.contentView.subviews objectAtIndex:0] として毎回0番indexのものを削除するとか、といった手段もあります。

    返信削除