役に立つかどうかよくわからないTipsシリーズ
とある重い処理を行う時
メインスレッドとは別のスレッドでやりたいときは多いですね
そんなときに使うベタな手法がGCD(Grand Central Dispatch)なわけですが
そのまま書くとこんな感じになるかなと思います
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// 何か重たい処理
dispatch_async(dispatch_get_main_queue()) {
// UIの処理
}
}
このdispatch_async()
に渡す引数は、小難しい話になるので
GCDについて情報整理する
↑こちらの方の記事にお任せするとして
複雑なスレッド処理をしないかぎりは、
この書き方で大抵のものは成立します
しかし、書くことが長いし、
もしiOS初心者には初見で何やってるのかよくわからないかも…なので
まずはラッピング関数を用意してしまいましょう
/// メインスレッドで処理を行う
/// - parameter block: メインスレッドで行う処理
func onMainThread(block: ()->()) {
dispatch_async(dispatch_get_main_queue(), block)
}
/// メインスレッド以外の新しいスレッドで処理を行う
/// - parameter block: 新しいスレッドで行う処理
func onNewThread(block: ()->()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block)
}
こうすると、先ほどの実装は
onNewThread {
// 何か重たい処理
onMainThread {
// UIの処理
}
}
いかがでしょう?
「あー、新しいスレッドで何かやって、メインスレッドで何かやってるんですねー」って
何をしているか分かりやすくなったと思います
で、
あともう少し工夫を
別スレッドに回す時って
メインスレッドに居て
重い処理をやるために別スレッドに処理を書いて
終わったらメインスレッドに戻す
って流れになることが多いので
こういう関数を作ってみました
/// 非同期処理を行う
/// - parameter async: 非同期でやりたい処理(別スレッドで実行)
/// - parameter completed: 完了時に行う処理(メインスレッドで実行)
func async(process asynchronousProcess: ()->(), completed completionHandler: ()->()) {
onNewThread {
asynchronousProcess()
onMainThread {
completionHandler()
}
}
}
使うときは、このような実装になります
async(
process: {
// 何か重たい処理
},
completed: {
// UIの処理
}
)
好みかもしれませんが
UIViewでのアニメーションを書く時の
この書き方に近しいものになるかと思います
UIView.animateWithDuration(
0.1, // 0.1秒間で
animations: {
// こんなアニメーションを行って
},
completion: { _ in
// 終わったらこれをやるよ
}
)
なので、すっきりして個人的に満足です
これらを使って、こういう関数も作成できます
/// 秒を指定して非同期でスリープを行う
/// - parameter seconds: スリープ秒数
/// - parameter completed: スリープ完了時に行う処理
func asyncSleep(seconds sec: UInt32, completed: ()->()) {
async(process: { sleep(sec) }, completed: completed)
}
/// ミリ秒を指定して非同期でスリープを行う
/// - parameter milliseconds: スリープのミリ秒数
/// - parameter completed: スリープ完了時に行う処理
func asyncSleep(milliseconds msec: useconds_t, completed: ()->()) {
async(process: { usleep(msec) }, completed: completed)
}
/// スリープ間隔を指定して非同期でスリープを行う
/// - parameter duration: スリープ間隔
/// - parameter completed: スリープ完了時に行う処理
func asyncSleep(duration: NSTimeInterval, completed: ()->()) {
async(process: { usleep(useconds_t(duration * 1000000)) }, completed: completed)
}
使用例
showIndicator() // インジケータを表示して
asyncSleep(0.8) { // 0.8秒待ったら
hideIndicator() // インジケータを隠す
}
普通にスリープ関数使うとできないことが、簡単にできるようになると思います