[Swift][iOS]TableViewのセル再利用の罠


はじめに

iOSアプリでGUIを作る際にはTableviewを使うことが非常に多いと思います。
このTableview、デフォルトだとセルのクラスはUITableViewCellで、表示出来るUIが事前に定められています(テキスト、サブテキスト等)。
たとえば画像を表示したかったり、ボタンを表示したかったり、実装したいUIによってはデフォルトのクラスを継承したカスタムクラスを作ってやる必要があります。
そんな際にバグってしまったセルの取扱いについてまとめておきます。

バグった実装

例によってカスタムクラスをつくって、内部にはUITextFieldを設置して、ユーザーの入力を受け付けるようにすると、以下のようなバグが発生しました。
①1行目のセルのTextfieldに文字列を入力すると

②下にスクロールすると7行目くらいのセルに文字列が入力されてしまっている

バグの内容

実装したUIはセルの数が一定ではなく、ユーザーの入力によりセルが増減するものになります(初期状態はセルはひとつ)。セルを増やした際、1番目のセルに文字列を入力すると、それが「画面外の7番目くらいの別のセルにも反映されてしまう」バグに遭遇しました。

原因

ぐぐったら以下のQiitaの記事に辿りつきました。

UITableViewのあるセルに設定した値が、他のセルにも反映されてしまう
https://qiita.com/shikatani/items/88dff6ecf9684027862e

要は画面外にあるセルは内部的には描写されておらず、必要に応じて描写されるようになっているようです。
画面外から画面内に入ってくるセルは、画面内から画面外に出ていくセルを再利用しているのです。

対策

セルに登載されるデータはcellForRowAtで指定する訳ですが、事前にデータが固定されていないと実装が複雑になる感があります。今回の件は動的に登載されるべきデータが変更されることから、単純な実装ではうまくいかなかった訳です。上記のQiita記事では、バグは発生しているものの登載されるべきデータは静的に事前に指定されているので、セルを初期化すれば解決しています(∵画像の読み込み先URLは事前に決定されているから)。しかしながら本件のようなユーザーの入力にデータが依存するケースだと、入力されるデータを逐次保存しておかないと対応出来ないと思います。すなわち、予めセルに登載するデータ(=配列)を指定しておき、その配列の中身が更新される、という実装が必要になるかと。

終わりに

具体的な解決策は提示出来てませんが、Tableviewのセルに登載するデータは事前に指定してあげないと予期せぬ動作をするという事と、ググれば何でも出てくるという事を伝えたかった。