iOS4でiOS SDKにも追加されたBlocksは、いまでは多くのiOS標準ライブラリで使われています。バックグラウンドで作業を行わせて、作業が終わったときのコールバックや結果を取得する事が出来ます。確かに、スムーズなUIを実現するのに便利なのですが、ときどき、プログラムの流れを崩したくないので、順序立てて動作してほしいと思うときがありますね。例えば、ALAssetで画像を取得するときも、画像を順番にアップロードしたいなどの要望があります。そのときにALAssetをsyncronizeに取得するメソッドを書きました。
ポイントがいくつかあります。
-
Dispatch Semaphore
-
GCDオブジェクトのメモリ管理の振る舞い
エキスパートObjective-Cプログラミングの説明を引用すると、
Dispatch Semaphore は、マルチスレッドプログラミングでは計数型セマフォとして知られるカウンタを持ったセマフォです。セマフォとは、交通機関における手旗信号です。通ってよいときは手 旗信号を上げ、通ってはいけないときは手旗信号を下げる、という具合です。Dispatch Semaphore では、カウンタを使ってそれを実現しています。カウンタが 0 のときは待つ、カウンタが 1 以上の ときは 1 減算して待たずに進む、となっています。
さすがに分かりやすいですね。つまり、dispatch_semaphore_signal
を通るとdispatch_semaphore_wait
で待っている部分が動き出すという事ですね。これをやる前は、NSRunloopで待たせていたのですが、メインスレッドがロックされてしまい、うまく待つ事が出来ませんでした。
こちらの解決策を参照しました。iphone – Wait for assetForURL blocks to be completed – Stack Overflow
これでAssetを同期的に取得する事が出来るので、
ALAssetsLibrary * library = [[ALAssetsLibrary alloc] init];
NSMutableArray* arrayURLString;
[arrayURLString enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL *stop) {
ALAsset* asset = [self.library getSyncAssetFromURL:[NSURL URLWithString:obj]];
UIImage * image = asset.defaultRepresentation.fullResolutionImage;
// image を使用する。
}];
のように、連続してAssetを使用する事が出来ます。
丁度、昨日今日で話題になっていた、GCDオブジェクトの振る舞い方の話しです。
iOS6(ARC)でのGCDのメモリ管理 – blog.ishkawa.org
@akisutesama @_ishkawa この挙動、OS_OBJECT_USE_OBJC マクロで制御可能です
— Yuichi Fujishigeさん (@nakiwo) 2013年3月21日
何も触らないと、Deployment TargetがiOS6.0以降の場合、GCDのオブジェクト(ここではdispatch_semaphore_t)がオブジェクトとして振る舞います。(実行環境でなくて、デバッグ時の環境なので、実行時でOSのバージョンを見て動作を変える必要はないです。)しかし、OS_OBJECT_USE_OBJCコンパイル変数に0を設定すると、Deployment Targetが6.0でもGCDの変数はオブジェクトとして振る舞わないので、Releaseしてあげる必要があります。
ですから、dispatch_semaphore_tを使う場合は、特に現在Deployment Targetが5の場合は、
#if OS_OBJECT_USE_OBJC!=1
dispatch_release(sema);
#endif
でチェックしておくと、後々DeploymentTargetを変えたときにも問題無くてよい感じですね。
こんな感じで、普段よく使うBlocksも、色々便利に使う事が出来ますねという話しでした。
「URL の分かっているALAssetをキューの流れを崩さずに取得する方法」への1件のフィードバック