LoginSignup
14
14

More than 5 years have passed since last update.

UITableView relaodData をバックグラウンドスレッドから呼ぶと大変なことになる話

Posted at

UIViewはスレッドセーフじゃないので、UIViewまわりの処理をバックグラウンドからやっちゃいけないのは常識なんですが、とはいえうっかりやっちまうことがあります。
うっかりやっちまうと、いわゆるボーアバグ的な状態になって、デバッグやってらんねーって状況になるし、そもそもバグの原因箇所をまともに見つけられなくなってお蔵入りになることすらあります。

普段からきちんと気をつけて記述しておいたり、NSAssertを使ったり
速度面に問題がないならむやみにバックグラウンドを使わなかったりというのが肝要ですが、今回は厄介な問題を見つけたのでご紹介。

willMoveToSuperViewなどのメソッドがバックグラウンドから呼ばれることがある

UIViewには、そのビューがaddSubviewされたとき(とか)に呼ばれる メソッドがあります。 以下の4種類です。

  • willMoveToSuperView
  • didMoveToSuperView
  • willMoveToWindow
  • didMoveToWindow

これらのメソッドは、UIViewControllerでいうviewWillAppearと似たノリで使えて便利なのですが、こいつらがバックグラウンドスレッドから呼ばれるケースがあることを発見しました。

まぁ表題のケースなんですが、UITableViewのreloadDataをバックグラウンドスレッドから呼んでしまうと、そこから生成するUITableViewCellの上記4メソッドがバックグラウンドスレッドから呼ばれます。 その中でUIViewを弄ってると、最悪の場合クラッシュします。 これ、スタックトレースにはどこが諸悪の根源なのかさっぱり書いてないので、追うのが大変です。

その他デバッグに便利な手法

  • NSAssertで[NSThread isMainThread]をチェックする
  • method_swizzlingでisMainThreadじゃなかったらデバッグログを吐く処理を本来のwillMoveToSuperView実行前に差し込む
  • 同様にmethod_swizzlingを用いて、UITableViewがreloadDataされる直前にisMainThreadをチェックするコードを差し込んでバグの原因を探る

雑感

Swiftで型安全になってもスレッドの問題はまだまだ解決しなそうなので、iOSアプリエンジニアとしては押さえておきたい知識です。

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14