yashiganiの英傑になるまで死ねない日記

週末はマスターバイクでハイラルを走り回ります

Swiftでマクロっぽいことをする

Objective-Cだと今でもマクロを使うことはあります. (ReactiveCocoaなんかも依存していますね.) プロダクトコードで使うのはできたら避けたいマクロですが,ビルド設定によって動作を切り替えたいときとかには結構便利です. しかしながら,Swiftにはマクロは存在しないので,このような手段を使って代替します.

Simple Macros

いわゆる定数を定義するマクロです. Swiftで定数を定義したいときはletを使うべきです.

#define FADE_ANIMATION_DURATION 0.35

このようなマクロによる定数の定義は,

let FADE_ANIMATION_DURATION = 0.35

letを使えば実現できます. マクロに比べ型チェックがされますので圧倒的にセキュアです.

筆者はこの他に定数を定義するのにcomputed propertyをよく利用します. structureやenum,グローバルコンテキストでも使えて便利なのでオススメです(特にenumで使うのがかっこいいです).

Complex Macros

例えば,MINMAXのような関数のように働くマクロはSwiftにはエクスポートされません. このタイプのmacroはCやObjective-Cでは型付けを回避するために使われますが,デバッグリファクタリングが非常に難しいです. Swiftではジェネリックタイプもありますので普通に関数で表現してください.

ちなみに,MINMAX相当の関数はこのように定義されています.

func min<T : Comparable>(x: T, y: T) -> T
func max<T : Comparable>(x: T, y: T) -> T

Build Configurations

ビルド時の設定によって動作を変更するときに使います. 以下のものがデフォルトで用意されています.

Function Valid arguments
os() OSX, iOS
arch() x86_64, arm, arm64, i386

例えば,iPhoneシミュレータのみで実行したいコードはこのように書けます.

#if os(iOS) && arch(i386)
// do something
#endif

よくあるチーム内配布のビルドでのみ実行したいなどの場合は,Other Swift Flagsを使ってください. Preprocessor Macrosに設定してもSwiftのコードでは参照できないので TARGETS > Build Settingsから-DBETATESTINGのように指定し,このように使います.

#if BETATESTING
// do something
#endif

まとめ

従来マクロでやっているようなことをSwiftで実現する代替テクニックを紹介しました. 特にOther Swift Flagsはよくなんだったっけ?となるので覚えておくとよいでしょう.

参考