この記事は何?
Swift 5.9から導入されたマクロについて、Appleの開発者向けドキュメントより「Applying Macro」を独自に解説する。
マクロは、コンパイル時に定型的に繰り返されるコードを生成する。
Swiftを基礎から学ぶには
自著、工学社より発売中の「まるごと分かるSwiftプログラミング」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。
概要
Swiftマクロは、コンパイル時にソースコードを部分的に生成するので、Swiftで反復的なコード記述を減らすことができる。
マクロの呼び出しは常に追加的に行われる。
マクロは、元のコードに新しいコードを追加するが、すでにプロジェクトの一部であるコードを変更したり、削除したりしない。
Swift標準ライブラリや多くのフレームワークは、多くのマクロを提供する。
独自のマクロを書くこともできる。
マクロはSwiftコードを生成するため、コードがマクロを使用するかどうかに関係なく、開発とデバッグに同じツールを使用すること。
マクロ展開の概要を示す図
左側は「元のSwiftコード」だけだが、右側には「マクロによって追加されたコード」がある。
マクロを呼び出す
マクロを呼び出す方法は、マクロを「宣言にアタッチ(添付)するかどうか」によって多少、異なる。
マクロを「宣言にアタッチする」には、マクロ名の先頭にアットマーク記号@
をつけて、その直後にマクロ引数を指定する。
これは、属性を書くのと同じ構文。
@Observable class MyObject {
public var someProperty: String = ""
public var someOtherProperty: Int = 0
fileprivate var somePrivateProperty: Int = 1
}
宣言にアタッチされたマクロはコードを生成して、そのコードを宣言に追加する。
たとえば、上記のObservable()
マクロは、MyObject
クラスにメンバーを追加してObservable
プロトコルを採用して、MyObject
をObservable
に準拠する。
宣言にアタッチせずにマクロを呼び出すには、マクロ名にシャープ記号#
をつけて、その直後にマクロ引数を指定する。
これは、#if
やその他のコンパイル時操作と同じ構文。
let messagePredicate = #Predicate<Message> { message in
message.recipient == "John Appleseed"
}
宣言に添付されていないマクロはコードを生成し、マクロを呼び出す場所にそのコードを追加する。
たとえば、上記のコードの#Predicate
マクロは、Predicate
構造体のインスタンスを作成する。
Predicate
型のドキュメントはこちら
マクロの詳細については、Swiftプログラミング言語を参照。
展開したマクロのコードを見る
プロジェクトをビルドすると、Swiftはコードを読み、マクロを呼び出す場所を探す。
その後、Swiftは各マクロの実装を呼び出して、コードを展開する。
最後に、Swiftは生成されたコードを含め、通常どおりプロジェクトをビルドする。
Xcodeでマクロが生成したコードを表示するには、マクロを呼び出すコードをクリックし、「Editor > Expand Macro」を選択する。
展開したコードを読んで「マクロの動作の詳細」を理解することができる。
また、拡張コードを使用してマクロを使用するコードをデバッグすることができる。
マクロによって生成されたコードにブレークポイントを設定することも可能。