【コラム】
前回は、Prototypeパターンの基本的な実装を紹介した。その結果、ある意味当然だが、Prototypeパターンではオブジェクトのコピーが重要な事が分かったと思う。
そこで、今回はObjective-CとCocoaにおける、コピー機能の紹介をしよう。非常に基本的な機能なのだが、議論すべき点はたくさんある。
まず、最も単純なコピーから考えてみよう。コピーする対象はオブジェクトなのだが、いくらオブジェクトといっても所詮はメモリ上のデータなので、同じサイズのメモリ領域を確保して値をコピーしてやれば、コピーは完了する。Objective-CはC言語とのハイブリッドなので、mallocとmemcpyを使えばいい。
といっても、それでは原始的すぎるので、Cocoaではオブジェクトの単純なコピーをサポートする関数が用意されている。NSCopyObjectだ。定義は次のようになる。
NSCopyObjectは、3つの引数を取る。最初の引数は、コピーの対象となるオブジェクト。2つ目は、コピーしたオブジェクトに、余分なメモリ領域を加えるかどうか指示する。たとえば、インスタンス変数の領域を増やしたいときなどに使えるだろう。3つ目の引数は、コピーを行うゾーンを指定する。ゾーンについては次回説明しよう。
この関数を使うと、オブジェクトのコピーは次のようになる。
これで、もとのオブジェクトとまったく同じオブジェクトができ上がる。
通常のメモリ領域のコピーならばこれで終わりだが、オブジェクトの場合は、これだけでは十分ではない。問題となるのは、インスタンス変数として、他のオブジェクトへの参照があるときだ。この場合、参照の値だけをコピーするのか、それとも参照しているオブジェクトもコピーするのかを、決めなくてはならない。
このとき、前者を浅いコピー(shallow copy)、後者を深いコピー(deep copy)と呼ぶ。NSCopyObjectによって行われるのは、浅いコピーだ。
|
また、Objective-Cならではの問題として、浅いコピーを行ったときに、オブジェクトに新たにretainを投げて参照カウントを増やすのかどうか、という問題もある。
どのスタイルのコピーを採用するのかは、オブジェクトごとに個別に対応する必要がある。そこで、コピーメソッドの実装のために提供されるのが、前回も紹介した、copyWithZone:メソッドなわけだ。このメソッドの中で、浅いコピー、深いコピー、retainを伴う浅いコピー、を必要に応じて実装する。
ちなみに、NSObjectにはcopyというメソッドが用意されているが、これはcopyWithZone:を呼び出すものなので、これを実装しているオブジェクトでしか呼び出す事ができない。それに対してNSCopyObjectは、単純にメモリをコピーするだけなので、すべてのオブジェクトに対して呼び出す事が可能だ。ただし、NSCopyObjectでは浅いコピーしかできないので、そのオブジェクトが意図するコピーを行うためにも、特別な場合を除いてcopyメソッドを使うべきだろう。
例を示そう。_titleというインスタンス変数を持つオブジェクトに、コピーメソッドを実装してみる。_title変数も、一緒にコピーしよう。
まず、allocとinitを使いコピーするオブジェクトを作る。そこに、copyWithZone:でコピーした_titleを設定している。これを、retainした_titleを渡すようにしてやれば、retainを伴った浅いコピーとなる。
インスタンス変数をコピーするには、copyWithZone:を使う方法と、alloc+initを使う方法とがあるだろう。これも、状況に応じて使い分ける事になる。
深いコピーは、インスタンス変数の構造が複雑になると大変だが、Cocoaによるサポートもある。たとえば、配列を表すNSArrayクラスには、保持しているオブジェクトを深いコピーするかどうかを指定できる初期化メソッドがある。先ほどのList 3.に、_namesというNSArray型の変数を付け加えて、深いコピーをしてみよう。
initWithArray:copyItmes:というメソッドを使ってコピーしている。2つ目の引数にYESを指定すれば、配列の中身をすべてコピーしてくれる便利なメソッドだ。NOを指定した場合は、retainを投げる事になる。
このように、一口に「コピー」といっても、気をつけなくてはいけない事はたくさんある。始めのうちは、浅いコピーと深いコピーは混同しやすいので、十分気を付けてほしい。
次回も、コピーにまつわる話を続けよう。
| トマトを食べれば痩せられる!? -京大ら、新発見の成分で肥満改善効果を実証 [21:00 2/10] |
| JAXA、液体シリコン中に残存する共有結合を観察 -大口径ウェハの実現に期待 [20:11 2/10] |
| NEDOなど、熱膨張が小さな樹脂複合材料ペレットの量産化に成功 [19:22 2/10] |
| 理研、一般顕微鏡を蛍光顕微鏡に強化できるアダプタを試作して性能を実証 [19:15 2/10] |
| 天の川のブラックホールが小惑星を飲み込んでいる - NASAが発表 [18:08 2/10] |
|
【連載】鉄道トリビア 第137回 山手線と京浜東北線から●●●が消えた!? [08:00 2/11] ライフ |
|
JRグループ、「周遊きっぷ」を見直し - 19の周遊ゾーンが3/31で販売終了に [07:30 2/11] ライフ |
|
「青春18きっぷ」春季用は2/20発売 - 夏季用・冬季用の発売は現時点で未定 [07:30 2/11] ライフ |
|
【ハウツー】炊飯器でつくるチャーシューが簡単すぎ、しかもおいしい! [07:00 2/11] ライフ |
|
【連載】出社前に。日常生活ですぐに使える! 英語クイズ 第118回 「どうぞお話しください、あなたが話す番です」ってなんて言う? [07:00 2/11] ライフ |