2014年12月5日金曜日

オフスクリーン描画をライブラリ化(全体設計編)

オフスクリーン描画機能をライブラリ化する話の続きです。今回は、全体設計の話を書きます。作り始める前に、どのような形で作るのか決めておかないと、無駄な作業が増えますからね。

 

私がオフスクリーン描画機能を使うのは、画面で表示する描画部品に加え、印刷内容を描くときです。いくつもの要素を描くのですが、同じ色で描く要素が多くあります。より具体的には、数十個の要素を、数色の色で描くという感じです。

実現したい動作としては、使う色をあらかじめ登録しておき、登録した色を指定しながら要素を描くという形です。複数の色を登録する機能、その色を使って図形や文字を描く機能が必須です。また、描くサイズを指定して描画を開始する機能、描き終わった内容をUIImageに出力する機能、描画を終了する機能も必要となります。

今回の描画機能は、クラスとして実現します。手短くまとめて、次のような全体像としました。

オフスクリーン描画機能のクラス
・描画の開始メソッド(描画サイズなどを指定)
・描画の終了メソッド(UIImageに出力して描画を終了)
・色の登録メソッド(線色と塗りつぶし色を指定:複数の登録が可能に)
・各種図形や文字の描画メソッド(登録した色を選択:大きさや線幅なども指定)

まとめると以上ですが、具体的に作り始めると、各種図形の部分が何種類にもなります。使うものから作り始めて、順次増やしていくのが現実的でしょう。

 

図形を描くメソッドと、色の登録メソッドを分けたのには、別な理由もあります。図形を描画するメソッドには、位置や大きさなど何個もの引数が必要です。これに色を加えると、引数が非常に多いメソッドになります。メソッドを使う側のソースコードには、引数が多いメソッドが並んで、美しくないですし、処理内容を読み取りづらくもなります。

色の指定を別なメソッドとして用意し、描画メソッドでは登録色を選ぶだけだと、描画メソッドの引数が減らせます。また、同じ色を何度も指定する無駄も解消できます。色の登録を別メソッドに分割することで、使う側のソースコードを読みやすくするという効果もあるのです。

 

全体像が決まったので、実現方法の検討に移ります。決めた形で実現できなければ、全体像を作り直さなければならないため、実現方法の検討は大事です。

iOSの描画機能では、色の指定も含めてCGContextを使います。まずCGContextを用意して、色や線の太さなどを設定します。設定したCGContextを指定しながら、目的の図形を描く命令を実行するという手順です。

最初は、次のように考えました。CGContextを複数保持して、それぞれのCGContextに色を設定します。図形を描く際には、目的の色に設定されたCGContextを指定して、描画命令を実行するという形です。

この考え方で実現できるかどうか、実験専用アプリで事前試験をしてみました。すると、大変なことが判明しました。必要な数だけCGContextを保持(変数で参照)したあと、あるCGContextを変更しても、全部のCGContextが変わってしまいます。当たり前ですね。同じCGContextを参照しているからです。

これを防ごうと、CGContextの深いコピーを作ろうとしました。でも、CGContextにはcopyメソッドが実装されておらず、コンパイルエラーになってしまいます。さらに、CGContextを新規で作る機能も用意されていないので、CGContextを複数保持して切り替えるという当初の案は暗礁に乗り上げてしまいました。

 

こんなことぐらいでは、あきらめきれません。こうなったら作戦変更です。CGContext自体を保持するのではなく、CGContextに設定する値を複数保持して、描画する直前にCGContextへ設定する方法を試します。

CGContextに設定できる属性は多数あります。全部を保持すると大変なので、今回は色だけに限ることにしました。線色と塗りつぶし色の2つだけです。この2つを登録できるだけでも、私に取っては十分に便利な描画機能になりますから。

この実現方法なら、あらためて実験する必要はありません。今まで使ったことのある機能の組み合わせで、簡単に実現できてしまいます。作成の障害はなくなりました。あとは実際に作るだけです。さらに細かな仕様は、これまでと同じように、実際に作るとき考えましょう。

 

作り始める前に考えたり実験したのは、以上のようなレベルまでです。ここまで整理できていると、あとは淡々と作り進むだけですね。実際、一気に作り終わりました。次回から、具体的なソースコードを紹介します。

0 件のコメント:

コメントを投稿