UITableViewCellの再利用と非同期処理の話。

「UITableViewのスクロールが遅いのは非同期処理を使ってないからである!」という主張に対して「不用意にdispatch_async一発とか危なくない?」というツッコミ。
10
sakamoto.kazuki @splhack

とりあえず「エキスパートObjective-Cプログラミング」読んだらいいんじゃないかな http://t.co/XcnhS1dsu9 Grand Central Dispatch, Grand Central Dispatch

2013-12-11 10:31:01
リンク 達人出版会 エキスパートObjective-Cプログラミング ― iOS/OS Xのメモリ管理とマルチスレッド iOSとOS Xの新機能「ARC」「Blocks」「Grand Central Dispatch」の解説本。Appleのリファレンスの和訳や解説にとどまらず、その実装を元に深く理解するための一冊。

スミヒロは酒飲み🍶 @sumihiro

よくある「tableViewCellの画像は非同期で」ってあるけど、普通にdispatch_asyncとかでやったらコールバックする前にセルが再利用されたらおかしくならない?それが怖くて手を出せないんやけど。 http://t.co/0nzxfIg70M

2013-12-11 09:28:50
スミヒロは酒飲み🍶 @sumihiro

昔のコードではNSOperationかなんか使って、セルが再利用されるタイミングを見て非同期処理を止めてたよな。GDCでもその辺りの細かい制御をやる必要があると思うけど、それをやってるコードを見たことが無い。大丈夫なの?

2013-12-11 09:29:08
Yuichi Fujishige @nakiwo

@sumihiro cellの中でやるんじゃなくて、cellの外側でロードして、ロードが終ったらcellにセット(見えている場合のみ)とかですかね

2013-12-11 09:34:20
スミヒロは酒飲み🍶 @sumihiro

@nakiwo 外部でやっても、外部でやってるのをキャンセルしないとリクエストキューがどんどん溜まって行きますよね?そこはいいのかなーとか。

2013-12-11 09:35:44
Yuichi Fujishige @nakiwo

@sumihiro キャンセルした方がいいですね。GCDだと確かにやりにくい

2013-12-11 09:36:49

もっさりさん @TeamMOSA2

@sumihiro 再利用がはいったらロードのキューをキャンセルすれば良いじゃない。

2013-12-11 09:36:23
スミヒロは酒飲み🍶 @sumihiro

@TeamMOSA2 そうなんですよ。そこまでやってるコードを最近見ないなーと。GDCは外部からキャンセル呼べないし、キャンセルさせるのが面倒なのかなーと。

2013-12-11 09:37:21
もっさりさん @TeamMOSA2

@sumihiro NSOperationを使えってずっとゆってるのにみんな聞く耳もたないからおかしな動きしてるとざまぁって思ってる。

2013-12-11 09:48:42
スミヒロは酒飲み🍶 @sumihiro

@TeamMOSA2 GDCもそこらへん同じようにフォローできればいいんでしょうけどねー

2013-12-11 09:49:45

Yuichi Fujishige @nakiwo

iOS 6以後ならtableView:didEndDisplayingCell:forRowAtIndexPath: というキャンセルに都合の良いメソッドが

2013-12-11 09:38:17
スミヒロは酒飲み🍶 @sumihiro

再利用されるタイミングでキャンセルしようとしても、非同期で動いてるスレッド自体を外部から止めることができないので、キャンセルフラグとか立てて非同期スレッドの中でそれを参照して止まってくれるのを待つしか無いよなー。

2013-12-11 09:40:06
スミヒロは酒飲み🍶 @sumihiro

再利用されるタイミングでキャンセルしようとしても、非同期で動いてるスレッド自体を外部から止めることができないので、キャンセルフラグとか立てて非同期スレッドの中でそれを参照して止まってくれるのを待つしか無いよなー。

2013-12-11 09:40:06
スミヒロは酒飲み🍶 @sumihiro

で、非同期スレッドが止まる前に再利用された新しいセルとして別の非同期スレッドが走り出すとなると停止フラグはオフにしておかないとまずい。前のスレッドが止まったことを確認して新しいスレッドを走らせるとか、特定のスレッドに対して停止信号を出すとか、相当気を遣う必要があると思うが。

2013-12-11 09:41:59
itok@そらかぜ @itokjp

結局従来通りにOperationQueueつかったほうがよいとか

2013-12-11 09:42:44
スミヒロは酒飲み🍶 @sumihiro

「画像をリサイズする」とかならセルが再利用されるまでの現実的な時間内に終わるかもしれんけど、「WEBからダウンロードする」とかなら確実に重複する可能性があるよな。

2013-12-11 09:43:05
itok@そらかぜ @itokjp

(Webからダウンロードなら、cellごとにrequest発行して、再利用されたときにまだrequestが完了してなければキャンセル、とかしてた)

2013-12-11 09:46:47

Nagisawks @nagisawks

@sumihiro 再作成でもそんなコストかからんかったりw

2013-12-11 09:52:51
残りを読む(25)

コメント

sawat1203 @sawat1203 2013年12月11日
この辺、難しいのでSDWebImageを使ってます。 https://github.com/rs/SDWebImage UIImageView+WebCache.h の setImageWithURL:〜 を呼ぶたびに前のリクエストが終わってなかったらキャンセルされますし、cancelCurrentImageLoadで明示的にキャンセルすることもできます。
0
やゆぐ @yayugu 2013年12月11日
ああ、実コードの方読んでいただければわかりますが、一応非同期からのcallbackでURL一致をチェクしておかしくはならないようにしてます。 あと真面目にやるなら非同期部分をtaskにしてcellがそのインスタンスを保持して、再利用時にtaskをcancelするのが正しいです。めんどうなのでやらなかったですが
0