こんにちは。SI部の鳥居です。

キャスレーではiPhoneなどのスマホアプリの開発もおこなっています。
私もiPhoneアプリの開発をおこなっていますが、iPhoneのアプリを開発することになったのは、
前職にてガラケー、カーナビなどの組み込み開発をC言語でおこなっていたところ、Cというキーワードから
Objective-CでのiPhone開発をおこなうことになった経験が今に生きています。

当然ながら組み込みと違うことは多々ありますので、iPhone開発で学んだことなどを書いていこうと思います。

■最適化
アプリのビルドにはおなじみのデバッグビルドとリリースビルドがあります。
このビルドの違いによって動作が異なるケースが稀にあるので注意が必要です。

この動作の違いはコンパイラの最適化によるものです。
最適化をおこなうことでアプリのサイズは小さくなるなど、リリースする上では必須かと思います。

最適化をした状態だと、ブレイクポイントを設定してのデバッグが困難になりますが、
デバッグ時にも最適化の設定を行うには以下の場所をFastest,Smallest設定するのみです。

optimization_level

同じ現象になれば、最適化が原因と考えられます。
ただ、最適化が原因だとしてもアプリが強制終了する場合には、解析しやすいですが、
落ちない場合にはログ等で地道に調べていく必要があります。

最適化が関係なくアプリが強制終了する場合には、Edit Scheme -> Argumentsから以下のオプションをつけるのがおすすめです。

NSDebugEnabled : YES
NSZombieEnabled : YES

debug_setting

これを入れておくと落ちるときにログが出力されることがあります。

その他、組み込みの時は解析に役立ったMAPファイルでしたが、iPhoneアプリでも生成することができます。
生成するには、以下のチェックをYesにつけます。

map_file

僕が試したときは特に利用できませんでしたが、場合によってはアプリが強制終了したときの
プログラムカウンタの位置とMAPファイルからおおよその関数が想定出来るかもしれません。

ただ、Xcode自体組み込みのガラケー開発に比べて解析などしやすいので、あまり頼ることは無いかもしれませんが、
困ったときの一助となればと思います。

■Blocks
Objective-Cにて最近使われる傾向の強いBlocksについてです。
iOSのバージョンアップに伴い、Blocksが使われていなかった関数でもBlocksを使う関数に置き換わる傾向が見受けられます。
この構文自体は、Cの関数ポインタに非常に良く似ています。

Blocksの構文
typedef void (^method)(int arg1, int arg2);

typedef 戻り値 (^Blocks名)(引数);
のようになっています。

ちなみに、関数ポインタは
typedef void (*method)(int arg1, int arg2);
になります。

^ が *になったというか、* が ^になった感じです。

どのようなときに使うかと言いますと、コールバックとして使用します。
関数を実行した結果のコールバックをうけ、そのときの処理を書きます。

 - (void)presentViewController:(UIViewController *)viewControllerToPresent
                      animated:(BOOL)flag
                    completion:(void (^)(void))completion NS_AVAILABLE_IOS(5_0);

モーダルビューを表示するときに呼び出す関数です。
iOS5以降に対応した関数で、いままでのモーダルビュー表示関数はiOS6までしか使用できません。
iOS7が出たら、上記の関数のみ使用可能になります。

この関数の最後の引数の
completion:(void (^)(void))completion
がBlocksです。呼ばれるのは画面を閉じたタイミングです。
ここで呼ばれても処理する必要のないときは、nilを設定すればOKです。

 [self presentViewController:nextView animated:YES completion:nil];

Blocksの書き方は、画面を閉じるときの処理と、画面が閉じた後の処理がソースコード上で
スクロールなしに確認できる点かと思います。

アニメーションの処理を書く際のUIViewの関数もBlocksにて制御できます。

+ (void)animateWithDuration:(NSTimeInterval)duration
                      delay:(NSTimeInterval)delay
                    options:(UIViewAnimationOptions)options
                 animations:(void (^)(void))animations
                 completion:(void (^)(BOOL finished))completion;

こちらは
animations:(void (^)(void))animations
にアニメーションの動作を書きます。

completion:(void (^)(BOOL finished))completion
には、アニメーション終了後の動作を書きます。

Blocksはポインタに似ていると書きましたが、ポインタについて記しておきます。

ポインタは
int *value;
のように書きます。

よく、その値のアドレスという言い方をしますが、その値にアクセスする際の
アドレスになります。

int a = 1;
int *b;
b = &a;

と書くと、bの値は1になります。

今、aとbは同じ場所(アドレス)の値を指しているので、

a++;
 (*b)++;

とすると、a, *b ともに3 になります。
a++;で2になり、(*b)++;で3になります。

例題として

#include <stdio.h>

void pointerTest1(int *val)
{
    (*val) += 2;
}

void pointerTest2(int val)
{
    val += 2;
}

int main(void)
{
    int value = 1;
    pointerTest1(&value);
    pointerTest2(value);
    printf("value = %d¥n", value);
    return 0;
 }

ですが、解答は”3″になります。
pointerTest1は引数にアドレスを渡しているので、main関数のint valueに対して変化が加えられます。
一方、pointerTest2は引数に渡された値(スタックの値)に変化を加えているのみのため、
main関数にあるvalueに値の変化はおこりません。

■新しいOSで追加されたFramework
iOSのバージョンがあがった際にFrameworkが追加されることがあります。
このFrameworkを使用したいけど、そのFrameworkに対応していないOSもサポート対象にしたい場合には、
非対応のOSでの起動時にアプリケーションが強制終了します。

このときの対処法ですが、Link Binary With Libraries の該当Frameworkに指定されているRequiredを
Optionalに変更することで回避できますので、お試しください。

optional

なお、実際にそのFrameworkを使う箇所では、OSを確認するなどして呼び分けるようにしないと
強制終了してしまうので、注意してください。

いかがでしたでしょうか。
インターネット上で検索することで見つかることも多々ありますが、その中の一つの情報としてお役に立てればと思います。