プロジェクト作成時に用意したほうがいいこと

この記事は[iOS Second Stage Advent Calendar 2013](http://qiita.com/advent-calendar/2013/ios-2)の13日目の記事です。

今回、`NSNull`で定義されてる`NSNull`のシングルトンインスタンスを返す`+ null;`とか、よくわからんことを書こうと思ってました。（よく考えると、iOSというよりObjective-C）

しかし、既に`NSNull`について詳しく書かれている[記事](http://qiita.com/yimajo/items/c9338a715016e7a812b1)を見つけてしまいました。。

なので、書くネタなくなりました。

つまり、13日は書くネタを何にしようかなーとずっと迷っておりました。（これが遅れた原因。嘘じゃない。嘘やないや…すみません…）


結局書く事が13日に決まらず、帰宅中の13日の23:40にやっと書く事が決まりました。そして書いてる間に寝落ちしてました。

さて、今回のAdvent Calendarのお題は「プロジェクト作成時にやっておいたほうがいい事」です。

それでは、本題に入りましょう！

※今回の参考コードを載せましたが、載せる程度だったのでFacebookとGAIのライブラリが入ってないゆえにエラります。

- [github.com/kaneshin/AdventTest](https://github.com/kaneshin/AdventTest)

時間があったらちゃんと整理しますー


## バージョントラッキング

自分の中で、アプリのバージョンは`1.2`のように [major version].[minor version] となるようにしています。

そして、ビルドバージョンは`1.2.3`のように [major version].[minor version].[patch version] となるようにしています。

このアプリバージョンの方をアプリ起動時に`NSUserDefaults`で保持しておき、ユーザがアプリのバージョンアップをしたのがわかるようにしたほうがよいです。（経験則）

何故かというと、初回インストール後の起動時に何か出したい！とか、アップデート後の起動で何かしたい！とか、絶対あるんですよね。

そして、その何かしたいときに前のバージョンで用意しておかないと出来ないので、プロジェクト立てた時点で用意しておくと絶対に良いです。

以下、コード抜粋（コードはgithubに上げてます）

```objc
- (ATAppVersionState)appVersionState
{
    NSString *trackingAppVersion = [ATObject getTrackingAppVersion];
    NSString *currentAppVersion = [ATObject appVersionString];
    ATAppVersionState state = ATAppVersionStateNotChanged;
    if (trackingAppVersion == nil) {
        state = ATAppVersionStateFirst;
        [[NSNotificationCenter defaultCenter] postNotificationName:kATAppVersionStateFirst object:nil];
        if ([_delegate respondsToSelector:@selector(appVersionStateFirst)]) {
            [_delegate appVersionStateFirst];
        }
    } else if (![trackingAppVersion isEqualToString:currentAppVersion]) {
        state = ATAppVersionStateBumpedUp;
        [[NSNotificationCenter defaultCenter] postNotificationName:kATAppVersionStateBumpedUp object:nil];
        if ([_delegate respondsToSelector:@selector(appVersionStateBumpedUp)]) {
            [_delegate appVersionStateBumpedUp];
        }
    } else {
        [[NSNotificationCenter defaultCenter] postNotificationName:kATAppVersionStateNotChanged object:nil];
        if ([_delegate respondsToSelector:@selector(appVersionStateNotChanged)]) {
            [_delegate appVersionStateNotChanged];
        }
    }
    if (state > ATAppVersionStateNotChanged) {
        [ATObject setTrackingAppVersion];
    }
    if ([_delegate respondsToSelector:@selector(appVersionState:)]) {
        [_delegate appVersionState:state];
    }
    return state;
}
```

トラッキングバージョン（既に保持しているもの）と、今のバージョンを比較しています。

- トラッキングバージョンが無ければそのアプリは初回インストール
- トラッキングバージョンが存在し、トラッキングしてるのと今のバージョンが違う場合はバージョンアップ
- 上記満たさなければ変化なし

です。

これをうまく利用すれば`NSFoundation`の判定もできるので、ユーザがiOSのバージョンアップしたのもわかります。（コードにそれっぽいの載せてます）


また、アプリやAPIで使用するアプリのバージョンは`int`または`double`に変換したものを利用したほうがいいです。（1.2などをそのまま使用しない）

```objc
+ (NSString *)appVersionString
{
    return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
}

+ (NSString *)appBuildVersionString
{
    return [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey];
}

+ (NSNumber *)appVersionNumber
{
    NSString *appVersionString = [ATObject appVersionString];
    NSArray *array = [appVersionString componentsSeparatedByString:@"."];
    appVersionString = [NSString stringWithFormat:@"%d%02d", [array[0] integerValue], [array[1] integerValue]];
    return [NSNumber numberWithInteger:appVersionString.integerValue];
}

+ (NSNumber *)appBuildVersionNumber
{
    NSString *appVersionString = [ATObject appVersionString];
    NSArray *array = [appVersionString componentsSeparatedByString:@"."];
    appVersionString = [NSString stringWithFormat:@"%d%02d.%02d", [array[0] integerValue], [array[1] integerValue], [array[2] integerValue]];
    return [NSNumber numberWithDouble:appVersionString.doubleValue];
}
```

しっかりとintやdoubleに直しておくと、値の大小でバージョンの切り分けができるからです。


## クラッシュトラッキングフレームワーク

- [Crashlytics](http://try.crashlytics.com/)
- [bugsense](https://www.bugsense.com/)

上記二つはアプリがクラッシュした際にレポートを送ってくれるツールです。

アプリがクラッシュしても「どういう状態起こったのかなんてわからぬ！！」なんで、これらのフレームワークを導入してレポートを見れると非常に心強いです。

これは12日に発表した[muukii0803](http://qiita.com/muukii0803)が弊社アプリに導入してくれました。

当分はここに出てくるレポートを減らすのが目標となりそうです。


## CocoaPods

- [CocoaPods](http://beta.cocoapods.org/)

言わずもがな、有名な`CocoaPods`ですが、先日、導入していなかったプロジェクトから移行する際に意外と大変でした。

ライブラリの管理については`git submodule`をやったりもしていましたがCocoaPodsが一番いいですし、CocoaPodsに存在しないライブラリはあまり使わない方が良い気もします。

※大変だった理由が、GoogleAnalytics for iOSに嵌りました。たしか静的ライブラリが入ってなかったとかだった気が。。


## バージョンアップが頻繁に起こるライブラリのラッパークラス・ヘルパークラス

GoogleAnalyticsやFacebook SDKってバージョンアップするとメソッド自体変わって、マイグレーションがマジ半端ないです。

だからといってそのバージョンで放置してても良くないので、私の場合はヘルパークラスを作成してその中に処理を書くようにしました。

メソッド名は単純で、`application:didFinishLaunchingWithOptions:`に記述する必要がある場合、そのヘルパークラスに同様の命名をして、呼び出します。

そうしておけばコードが散り散りとならず、メンテ性が確保できます。

この参考となりそうなコードもgithubにあげたものへ一部載せてあります。



今回紹介したアプリプロジェクトに入れておいたほうがいいものは、実際にアプリを開発し続け、しっかりと運用をしないと意外と気付かないものです。