まとめの限定公開に「リンク限定」が追加されました。URLを伝えてまとめを共有しよう!

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

「UITableViewのスクロールが遅いのは非同期処理を使ってないからである!」という主張に対して「不用意にdispatch_async一発とか危なくない?」というツッコミ。
プログラミング
15862view 2コメント
10
sakamoto.kazuki @splhack
とりあえず「エキスパートObjective-Cプログラミング」読んだらいいんじゃないかな http://t.co/XcnhS1dsu9 Grand Central Dispatch, Grand Central Dispatch
リンク 達人出版会 エキスパートObjective-Cプログラミング ― iOS/OS Xのメモリ管理とマルチスレッド iOSとOS Xの新機能「ARC」「Blocks」「Grand Central Dispatch」の解説本。Appleのリファレンスの和訳や解説にとどまらず、その実装を元に深く理解するための一冊。

ヤバいスミヒロ @sumihiro
よくある「tableViewCellの画像は非同期で」ってあるけど、普通にdispatch_asyncとかでやったらコールバックする前にセルが再利用されたらおかしくならない?それが怖くて手を出せないんやけど。 http://t.co/0nzxfIg70M
ヤバいスミヒロ @sumihiro
昔のコードではNSOperationかなんか使って、セルが再利用されるタイミングを見て非同期処理を止めてたよな。GDCでもその辺りの細かい制御をやる必要があると思うけど、それをやってるコードを見たことが無い。大丈夫なの?
Yuichi Fujishige @nakiwo
@sumihiro cellの中でやるんじゃなくて、cellの外側でロードして、ロードが終ったらcellにセット(見えている場合のみ)とかですかね
ヤバいスミヒロ @sumihiro
@nakiwo 外部でやっても、外部でやってるのをキャンセルしないとリクエストキューがどんどん溜まって行きますよね?そこはいいのかなーとか。
Yuichi Fujishige @nakiwo
@sumihiro キャンセルした方がいいですね。GCDだと確かにやりにくい

もっさりさん @TeamMOSA2
@sumihiro 再利用がはいったらロードのキューをキャンセルすれば良いじゃない。
ヤバいスミヒロ @sumihiro
@TeamMOSA2 そうなんですよ。そこまでやってるコードを最近見ないなーと。GDCは外部からキャンセル呼べないし、キャンセルさせるのが面倒なのかなーと。
もっさりさん @TeamMOSA2
@sumihiro NSOperationを使えってずっとゆってるのにみんな聞く耳もたないからおかしな動きしてるとざまぁって思ってる。
ヤバいスミヒロ @sumihiro
@TeamMOSA2 GDCもそこらへん同じようにフォローできればいいんでしょうけどねー

Yuichi Fujishige @nakiwo
iOS 6以後ならtableView:didEndDisplayingCell:forRowAtIndexPath: というキャンセルに都合の良いメソッドが
ヤバいスミヒロ @sumihiro
再利用されるタイミングでキャンセルしようとしても、非同期で動いてるスレッド自体を外部から止めることができないので、キャンセルフラグとか立てて非同期スレッドの中でそれを参照して止まってくれるのを待つしか無いよなー。
ヤバいスミヒロ @sumihiro
再利用されるタイミングでキャンセルしようとしても、非同期で動いてるスレッド自体を外部から止めることができないので、キャンセルフラグとか立てて非同期スレッドの中でそれを参照して止まってくれるのを待つしか無いよなー。
ヤバいスミヒロ @sumihiro
で、非同期スレッドが止まる前に再利用された新しいセルとして別の非同期スレッドが走り出すとなると停止フラグはオフにしておかないとまずい。前のスレッドが止まったことを確認して新しいスレッドを走らせるとか、特定のスレッドに対して停止信号を出すとか、相当気を遣う必要があると思うが。
itok@そらかぜ @itok_twit
結局従来通りにOperationQueueつかったほうがよいとか
ヤバいスミヒロ @sumihiro
「画像をリサイズする」とかならセルが再利用されるまでの現実的な時間内に終わるかもしれんけど、「WEBからダウンロードする」とかなら確実に重複する可能性があるよな。
itok@そらかぜ @itok_twit
(Webからダウンロードなら、cellごとにrequest発行して、再利用されたときにまだrequestが完了してなければキャンセル、とかしてた)

Nagisawks @nagisawks
@sumihiro 再作成でもそんなコストかからんかったりw
残りを読む(25)

コメント

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