iOSプログラミングの注意点 (その1

Objective-Cを使ったiOSアプリケーション開発を初めてから半年以上経ち多少は慣れてきた。その中で他のプラットホームと比べてiOS上でのプログラミングで注意すべき点を幾つか上げていこう。

EXC_BAD_ACCESS


恐らくiOSプログラミングを初めて最初に遭遇するクリティカルなエラーはEXC_BAD_ACCESSだろう。
このエラーの原因の殆どは既に解放されたメモリ領域(大抵はオブジェクトを指していたポインタ変数)にアクセスすることだ。

Xcode環境ではコンパイル時のオプションで解放済みの変数に対してNSZombieオブジェクトをセットすることでデバッグを容易にする仕組みがあり、そのためにこのエラーを「ゾンビオブジェクトの発生」等とも呼んだりする。(解放済みのオブジェクトをアンデッドに例えるのは面白いと思う)

objective-Cでは変数は生成されて所有権を設定(retain)することで参照カウントが増加し、スコープを超えるか明示的にnilをセットして所有権を破棄(release)することで参照カウントが減る。参照カウントが0になるとメモリ領域は解放されてアクセス不可能となる。(ARC(Automatic Reference Count)をオンにした環境ではこの処理をコンパイラが自動的に行ってくれる)

このことを理解していないエンジニアやjavaC#などGC機能が実装されているプラットホームしか経験の無いプログラマは宣言した変数がどうして勝手に解放されるのか、最初は訳が分からないことだろう。

EXC_BAD_ACCESSを発生させる。

現在のXcodeはARCがデフォルトでOnに設定されているので、EXC_BAD_ACCESSは簡単には発生しない。
なので、故意に変数をARCの制御下から外してスコープから外れた時点で解放されるようにコードを書く。
具体的には

このように変数に"__unsafe_unretained"属性を付けて書くとメソッド"prepareZombee"メソッドで戻る文字列は生成時に所有権が設定されず参照カウントが増加しない(retainされない)。なのでスコープから抜けるとreleaseされて参照回数が減じられると領域が解放されてしまうため、UITextFieldにセットしようとアクセスした所でEXC_BAD_ACCESSが発生する。コンパイル時のオプション"NSZombieEnabled"属性をオンにすることで冒頭のSSのようにInstrumentationで解放済みのオブジェクトをプロファィルすることができる。

最初は戸惑うが、objective-Cのオブジェクトのスコープと所有権、参照カウントと解放の仕組みを理解することでEXC_BAD_ACCESSが発生しても直ちに修正することができるだろう。