ARCを使用したメモリ管理の基礎

iOSアプリのメモリ管理についてまとめました！
何かあったらコメントどぞー。

>6/24：コメントで間違いを指摘されたので、色々テキスト修正しました。

##メモリ管理に気をつけないとどうなるの？

###動作がもっさりする
使い終わったオブジェクトを解放していないパターン。
解放されないのでどんどん使用メモリが増えていき、メモリ圧迫しちゃってもっさりする。
同じ端末で動かしている他のアプリも影響を受けてしまうので気をつけましょう！！

###アプリが落ちる
よくあるのがEXC_BAD_ACCESSのパターン。
アクセスしようとしたデータが既に解放されちゃっているというエラー。
解放するタイミングにも気をつけましょう！！


##気をつけるポイント

- <del>strongなプロパティは自分で解放する</del> (誤解してました…。自動で解放されるよう)
- プロパティ属性を理解する
- 解放するタイミング
- メモリ不足時の挙動を理解する
- Blocksの循環参照に気をつける


##プロパティ属性を理解する
プロパティ属性とは、この括弧の中に書かれているやつです。

```objective-c:
@property (nonatomic, strong) NSString *message;
```

これをちゃんと理解して使い分けないと、いつの間にかデータが変わっていたり、循環参照が発生してメモリが解放されなくなったりするので注意が必要です。
これについては、ひじょーーに分かりやすくまとまっている記事があったので紹介します。

- [[iOS5] ARC (Automatic Reference Counting) : Overview - iOS 開発ブログ Natsu's note](http://blog.natsuapps.com/2011/11/ios5-arc-overview.html)
- [[iOS5] ARC : プロパティ属性と使い方 - iOS 開発ブログ Natsu's note](http://blog.natsuapps.com/2011/11/ios5-arc-property.html)
- [[iOS5] ARC : 循環参照 - iOS 開発ブログ Natsu's note](http://blog.natsuapps.com/2011/11/ios5-arc-strong-reference-cycle.html)

あとこちらのガイドラインも参考になるのでおすすめです。

- [Objective-C のプロパティ属性のガイドライン #Objective-C #Mac #iOS #Xcode - Qiita [キータ]](http://qiita.com/items/80660f9aa20afaf671f3)


##解放するタイミング

次は解放するタイミングです。

基本、解放するタイミングは、`viewDidDisappear` や `dealloc` です。
最初、`viewDidUnload`に解放処理を入れると誤解していたのですが、iOS6からは全く呼ばれなくなっています。(iOS5でもメモリ不足時にしか呼ばれない)


表示する時だけ必要なものは、`viewDidAppear`で生成して`viewDidDisappear`で解放。生成コストが高かったり、表示していない時も必要なものは、`viewDidLoad`で生成して`dealloc`で解放。という感じでしょうか。


どういったデータを解放する必要があるのかというと、ARCのドキュメントに書いてありました。

引用：[ARCへの移行のリリースノート | Second Flush](http://secondflush2.blog.fc2.com/blog-entry-1087.html)

> **・自分のオブジェクトのためにdeallocメソッドを記述する必要はまだありますか？**
>
> おそらく
> 
> ARCはmalloc／free、Core Foundationオブジェクトの寿命の管理、ファイル記述子などを自動化しておらず、そのようなリソースは依然としてdeallocメソッドを記述することによって解放します。
> 
> インスタンス変数を解放する必要はありません（実際にはできません）が、ARCを使用してコンパイルしていない他のコードやシステムクラス上で[self setDelegate:nil]を呼び出す必要があるかもしれません。
> 
> ARCでのdeallocメソッドは[super dealloc];の呼び出しを必要と（または許可）せず、superへのチェーニングはランタイムによって適用と処理がなされます。

今の所これに当てはまるようなコードは書いた事がないので、それほど意識するケースは少ないのかもしれませんね。インスタンス変数も自動で解放してくれるようなので、解放というか例えば、NSNotificationCenterにaddObserverしたのをremoveするとか、そういう使い終わった事を示す処理を入れるケースが多そう。


あと、メモリ使用量が多いオブジェクトは、didReceiveMemoryWarning でも解放しときましょう。


##メモリ不足時の挙動を理解する
この辺をちゃんと理解しとかないと、メモリ不足時に EXC_BAD_ACCESS が発生して落ちるので要注意。


メモリ不足時には、以下のような処理が実行されます。

- 全ViewController で、didReceiveMemoryWarning が呼ばれる
- iOS5の場合、最前面以外のViewControllerで viewDidUnload が呼ばれる

iOS6の場合、メモリ不足時に viewDidUnload が呼ばれないので、メモリ使用量が多いオブジェクトは、didReceiveMemoryWarning で解放する必要があります。あとiOS5では viewDidUnload が呼ばれてviewが解放されるので、iOS6とは挙動が異なったりします。

参考：[iOS Viewライフサイクルまとめ、iOS6での変更点 | Zero4Racer PRO Developer's Blog](http://www.zero4racer.com/blog/929)


##Blocksの循環参照に気をつける
あとは、Blocksを使う時に陥りがちな循環参照にも気をつけましょう。
お互いに参照しちゃってデータが解放されないパターンです。
これもわかりやすい記事があったので紹介します。

- [Objective-CのBlocksの循環参照に関する僕なりのベストプラクティス | 三度の飯とエレクトロン](http://blog.katty.in/2612)


##以上です
最低限知っておく事はこれくらいかな。。
メモリ管理について調べるとARC以前の記事がよく引っかかったりしますが、それに比べると大分楽になってますねー。

ただ、ARCであまり意識する事は無くなったとはいえ、ちゃんと開発しようとするとその辺の知識が必要になってきます。勉強しときたいと思う方は、とりあえずこの本が安いので読んでおく事をおすすめします。

[エキスパートObjective-Cプログラミング ― iOS/OS Xのメモリ管理とマルチスレッド - 達人出版会](http://tatsu-zine.com/books/objc)


##追記
非常に参考になる記事を発見したので追記。
[Objective-C - ARC のメモリ解放タイミングを調べた - Qiita [キータ]](http://qiita.com/amay077/items/95a4139e6f553d8a56a1)