LoginSignup
22
26

More than 5 years have passed since last update.

DebugとReleaseで定義を切り替える3つ目のベストな方法

Last updated at Posted at 2017-05-10

ほとんどのアプリは以下の方法で分けていると思います。
一つは、User-Definedを使う方法。
一つは、プリプロセッサマクロを使う方法。

これらよりも、自分がベストだと思う方法があるよ。という記事です。

MavenのprofileやGradleのAndroid Pluginのように環境別のファイルを用意して、ビルドにどっちを使うかを判断させる方法です。

やり方

まずは、Environment-Info-develop.plistEnvironment-Info-production.plist のように環境ごとのファイルを作成します。
中身は以下のように環境ごとの違いを記述します。

Configuration/Environment-Info-develop.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>apiUrl</key>
	<string>https://develop.hoge.jp</string>
</dict>
</plist>
Configuration/Environment-Info-production.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>apiUrl</key>
	<string>https://hoge.jp</string>
</dict>
</plist>

次に、Build Phasesで、Run Scriptを作成します。
内容は、以下です。つまり、選択したBuild Configurationに対応するファイルをEnvironment-Info.plist としてアプリにバンドルさせています。

/bin/sh
BUILD_PRODUCT="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app"
PROJECT_PATH="${PROJECT_DIR}/${PROJECT_NAME}"
INFO_BUILD_PATH="${BUILD_PRODUCT}/Environment-Info.plist"

rm -rf "${INFO_BUILD_PATH}"
if [ "${CONFIGURATION}" = "Debug" ]; then
  cp "${PROJECT_PATH}/Configuration/Environment-Info-develop.plist" "${INFO_BUILD_PATH}"
  echo "Development Environment-Info copied into ${BUILD_PRODUCT}"
else
  cp "${PROJECT_PATH}/Configuration/Environment-Info-production.plist" "${INFO_BUILD_PATH}"
  echo "Production Environment-Info copied into ${BUILD_PRODUCT}"
fi

最後にこの内容を扱うクラスを作成して利用するだけです。
取得できなかった場合は単純なバグなので、すぐに落として気づけるように、Forced unwrappingさせます。

EnvironmentHolder.swift
public class EnvironmentHolder {

    static let sharedInstance = EnvironmentHolder()

    let apiUrl: String

    private init() {
        let bundle = Bundle.main

        let environmentPath = bundle.path(forResource: "Environment-Info", ofType: "plist")!
        let environmentDict = NSDictionary(contentsOfFile: environmentPath)!
        self.apiUrl = environmentDict.object(forKey: "apiUrl") as! String
    }
}

User-Definedとの比較

User-Definedは、Target > Build Settings で「+」を押下して 「add User-Defined Setting」 でConfigurationごとに設定していく方法です。

スクリーンショット 2017-05-09 13.46.44.png

そして、Info.plistに書いて

Info.plist
       <key>apiUrl</key>
       <string>${apiUrl}</string>

コードで以下のように呼び出します。

let apiUrl = Bundle.main.object(forInfoDictionaryKey: "apiUrl")

あまり、良くないところは、User-Definedが、*.xcodeproj/project.pbxproj に保存されることです。
開発中は、Debugの場合だけ書いておいて、後でコピペして本番用のを用意するということができません。

一方、最初に提案した方法は、ただのplistなので、簡単にコピペができますし、diffに気づきやすいです。

プリプロセッサマクロとの比較

Objective-cなら Preprocessor Macrosに、例えば、DEBUG=1 と書き、
Swiftなら Other Swift Flags に -D DEBUG と書き、

コードで以下のように呼び出します。

Objective-Cの場合

 #ifdef DEBUG
    // ...
 #elif RELEASE
    // ...
 #endif

Swiftの場合

  #if DEBUG
    // ...
  #elseif RELEASE
    // ...
  #endif

あまり良くないところは、本質的ではない処理がコード上に現れることです。値が少なければ良いですが、多くなると可読性が損なわれ、バグに気付きにくくなります。
この方法では、EnvironmentHolder.swiftのようなクラスを用意して、一つのクラスだけに閉じる戦略がいいでしょう。
いずれにしろ、最初に提案した方法は余計な分岐がないことがメリットになります。

22
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
26