[iOS] CALayer renderInContextして、画像を取得しても駄目なときはpresentationLayerを使う

2013/06/3

こんにちは。きんくまです。

前回UIViewのキャプチャの取り方について書いたのですが、あのあと上手く取れない場合があったので、メモです。

今回は、sublayerで動的に描画していた部分が空になってしまって、うまく取得できない状態でした。

解決方法は記事タイトルの通りなのですが、どうしたものかとCALayerのドキュメントを眺めていたら、良さそうなプロパティのpresentationLayerがあってそいつを使うと大丈夫でした。

具体的には、こんな感じ

+ (UIImage *)capturedImageWithView:(UIView *)aView
{
    UIGraphicsBeginImageContextWithOptions(aView.bounds.size, NO, 0);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGPoint pt = aView.layer.frame.origin;
    CGContextSaveGState(ctx);
    CGContextTranslateCTM(ctx, pt.x, pt.y);

    [[aView.layer presentationLayer] renderInContext:ctx]; //ココです!

    UIImage *tempImg = UIGraphicsGetImageFromCurrentImageContext();
    CGContextRestoreGState(ctx);
    UIGraphicsEndImageContext();
    return tempImg;
}

調べてみると、アニメーションしている場合もこれを使うと良いみたいです。

で、あとメインスレッドからこのメソッドを呼ばないと、原因不明でアプリが落ちる場合がありました。落ちたり落ちなかったり。

具体的には、renderInContext: を使ったときに、[なんかのObject drawLayer:inContext:] がunrecognized selectorだったり、Bad Accessみたいなエラーが出て落ちる感じです。なんかのObjectというのは、引数に読んでいるUIViewのsubviewの中の関連するオブジェクトだったりします。UIScrollViewDelayedTouchesBeganGestureRecognizerという、すごい長い名前のオブジェクトだったり、そうじゃなかったり、すごく不安定。

とにかくメインスレッドから呼ぶと、落ちなくなりました。

教訓)ViewやLayer関連をなんかするときは、メインスレッドから呼ぶべし!

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る