iOSやMacの開発において現在ではARC(Automatic Reference Counting)が前提となっており、MRCの時代と比べて飛躍的に簡単になりました。しかし、開発するアプリによってはMRCでメモリ管理をしたい場面が少なからずあるはずです。そんな時はObjective-C++の力を使って、ARCのように快適な開発をしましょう。
ユビレジで働いています。
さて、Objective-C++でMRCを使うシチュエーションが果たしてあるのか?はおいておいてこのような話をさせていただきます。
メモリ管理の話と、そして、なぜC++かの話が見えてくると思います。
後半でサンプルコードが出ますが、スライドの下の方にURLがあります。スライドも公開すると思います。
Objective-Cのメモリ管理
MRCでないのはARCです。ObjCで参照カウント方式のメモリ管理をコンパイラがやってくれます。
DefaultでYESになっています。
NOにすれば使わないことができますがSwiftはARCだけです。
ARCを使わず自分でメモリを管理するのがMRCです。
これがどのようなものか見ていきましょう。
TestClass *value = [[TestClass alloc] init]; [value retain] // 参照カウント2 [value release] // 参照カウント1 [value release] // 参照カウント0
Autoreleaseと言うのもあります。
[value autorelease]
とすることで開放を予約することができ、
@autorelasepool{ }
でかこまれた間を抜けると開放されます。
ARCとMRCでクラスを実装する時の違いを見てみます。
プロパティを書いてしまえばいいんですが、手動で実装したとしましょう。ARCです
MRCです
deallocでもreleaseをしたり。一つのインスタンスに対してこれだけコードを書きました。当時はみなさん苦労したのではないでしょうか。
そこで利用するのがObjective-C++です。
Objective-CとC++を共存して書けるということです。
拡張子を .mm
にすると書けます。C++との機能の呼び方の違いを見てみましょう。
だいたいこのような似た機能があります。
どんなコードが書けるのでしょうか
同じ関数の下2行はC++で書いています。
C++の関数と同じように書けます。
逆にC++のクラス定義にObjective-Cを書くこともできます。
メモリ管理はどうするでしょう
CppClass *pointer = new CppClass(); delete pointer
new で作って delete で消します。参照カウントはありません。 1回のnewに対して1回のdelete。
組み込み型と同じような書き方ではこうです。
Cpp Class value_1; ...... // 書き方はいろいろありますが全部同じです auto value_5 = CppClass(5)
値型のような扱いで、スコープを抜けると開放されます。
if の中で宣言すれば、出る時に開放されます。
メンバ変数はデストラクタが呼ばれると開放されます。
Objective-CのクラスにC++のメンバ変数を定義するとどうなるでしょう。
[super dealloc]
を呼ぶと開放されます。(allocが呼ばれた時点でコンストラクタが呼ばれています)
Objective-Cのオブジェクトを保持するC++のクラスを作るとMRCでも手軽に管理できないか
サンプルコードの一つのコードです
objc_ptr.hpp というクラス。チョットデキルひとなら簡単に読めると思います。
こんな構造です。
shared_ptrはC++で参照カウント方式でオブジェクトを管理するものです。new や delete をいい感じにしてくれるもの。
Objective-CのものをC++でshared_ptrを使えば、開放し忘れないという考えです。
TestClassをautoreleaseした状態で、objc_ptr にTestClassを保持させます
*
演算子を作って、先頭につければ中身が取り出せるようにしました。
参照カウントをそのまま保持するパターン
auto で変数の型推論をつかってシンプルに。
autoreleaseを外して保持するパターンです。
autoreleaseをほうっておくとメモリが溜まっていくので最初から外してしまおうというやつです。使うかどうかは必要次第ということで
これは弱参照で保持します
強参照されたものを渡すと弱参照で保持します。 lock
を呼ぶと強参照で取得できる。既に開放されていれば中身はありません。
weak self を使いたいときのために .to_weak も用意しました。
objc_ptrをインスタンス変数で使う例です。
ARCとMRCの違いをお見せした時と同じ構成で作っています。
MRC
作ったやつを利用
ほぼARCのように使えるようになっています。
使うはobjc_ptrを取り回すのが良いと思います。
改良の余地、展望
ARC環境下かMRCかでretainやreleaseをマクロで切り替えてコードを書くことがありますが、それも吸収して同じ書き方出かけるようになるのではないか
QA
- Objective-C++とObjective-Cは相性が良いと思うが、どのような必要でこういうことが必要になったのでしょうか
- オーディオプログラミングを良くするのですが、ARCをONにしていると音に影響がある気がしたことがあって、できるだけARCを避けたい。
- 音質?スピード?
- スピードですかね、途切れるような気がしました。ガベージコレクションのときも明らかに影響がありました。なのでARCも試したら、影響がある気がしました。もしかすると私の思い違いかもしれませんが。
- 音質?スピード?
- オーディオプログラミングを良くするのですが、ARCをONにしていると音に影響がある気がしたことがあって、できるだけARCを避けたい。
- ライブラリでMRCを使っていて、本体でARCをONにしている場合、本体を触るエンジニアがライブラリでARCで書いてしまう事故がよくある。そういうのの対策方法、良いアイディアはありますか
- CocoaPodsを使って勝手にやってもらうというのはありませんか。設定が違ってもファイル単位で設定できる。ライブラリをいじることは、、、ありますか?
- 内製だとあります
- うーん、それは、知見はないですねぇ。。
- 内製だとあります
- CocoaPodsを使って勝手にやってもらうというのはありませんか。設定が違ってもファイル単位で設定できる。ライブラリをいじることは、、、ありますか?
- Objective-C++はどれくらい新しいC++の文法を使えますか