Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swift Macroでメソッドの実行時間を計測できるようにしてみた
Search
Ryu-nakayama
October 25, 2024
Programming
1
160
Swift Macroでメソッドの実行時間を計測できるようにしてみた
2024/10/25 mobile.stmn #8の登壇資料です
Ryu-nakayama
October 25, 2024
Tweet
Share
More Decks by Ryu-nakayama
See All by Ryu-nakayama
作文ツール(Writing Tools)をアプリから制御する
ryunakayama
0
21
iOSアプリで測る!名古屋駅までの 方向と距離
ryunakayama
0
180
「ジェン文字」をアプリ内で使ってみよう
ryunakayama
0
73
SwiftDataと連携したWidgetを作ってみた
ryunakayama
1
110
Appleの審査担当の方とお話ししてみた!
ryunakayama
0
260
大公開!iOS開発の悩みトップ5 〜iOSDC Japan 2024〜
ryunakayama
0
320
Translation API について 〜WWDC24〜
ryunakayama
0
310
効率化に挑戦してみたらモバイル開発が少し快適になった話
ryunakayama
0
1.7k
新卒1年目がプロジェクトを進めるときにコケたポイント
ryunakayama
1
1.8k
Other Decks in Programming
See All in Programming
GPUを計算資源として使おう!
primenumber
1
150
Rubyでやりたい駆動開発 / Ruby driven development
chobishiba
1
740
20250628_非エンジニアがバイブコーディングしてみた
ponponmikankan
0
700
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
520
おやつのお供はお決まりですか?@WWDC25 Recap -Japan-\(region).swift
shingangan
0
140
レベル1の開発生産性向上に取り組む − 日々の作業の効率化・自動化を通じた改善活動
kesoji
0
230
A full stack side project webapp all in Kotlin (KotlinConf 2025)
dankim
0
120
生成AI時代のコンポーネントライブラリの作り方
touyou
1
230
AIと”コードの評価関数”を共有する / Share the "code evaluation function" with AI
euglena1215
1
170
git worktree × Claude Code × MCP ~生成AI時代の並列開発フロー~
hisuzuya
1
580
「テストは愚直&&網羅的に書くほどよい」という誤解 / Test Smarter, Not Harder
munetoshi
0
180
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
150
Featured
See All Featured
Scaling GitHub
holman
460
140k
Docker and Python
trallard
44
3.5k
Into the Great Unknown - MozCon
thekraken
40
1.9k
Writing Fast Ruby
sferik
628
62k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Code Review Best Practice
trishagee
69
19k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
960
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
970
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
What's in a price? How to price your products and services
michaelherold
246
12k
Side Projects
sachag
455
42k
Transcript
Swift Macroでメソッドの実行時間を 計測できるようにしてみた CP本部 iOSアプリ開発部 中山 龍 2024年10月25日 mobile.stmn #8
自己紹介 中山 龍 (なかやま りゅう) • 株式会社kubell ◦ 新卒2年目のiOSエンジニア(22) ◦
「Chatwork」アプリの開発を担当 • 愛知県在住 ◦ 日曜に引っ越しをし、熱田区民 → 中区民に @ryu_develop
今更ながらSwift Macro (Swift Syntax) で遊んでみたのでその内容を紹介します
注意事項 • 本スライドの内容や登場するコードは趣味で作成しているものであり、業 務で扱っているプログラム・プロダクト・開発環境とは一切関係ありません • 「試しに触ってみた」という趣旨の紹介であり、必ずしもベストプラクティス を紹介しているわけではありません • スライド・GitHubに掲載しているコードも完璧な動作を保証するものでは ありません
01 | Swift Macroとは
Swift Macroとは? - Swiftプログラム内でコンパイル時にコードを自動生成したり、変換したりする ための機能 - Swift5.9以降で導入 - @〜〜〜 や
#〜〜〜といった感じで使用する 参考: Swiftマクロの書き方 - WWDC2023 代表的なものだと - Observation (@Observable) - SwiftUIのプレビュー (#Preview) 強力で便利な機能だが、可読性などの観点から乱用しないように注意が必要!
02 | 実行時間を計測するMacroを書いてみた
完成イメージ 8 @(自作のMacro) 型に対して自作のMacroを付ける 型のメソッドを実行した時に、 実行したメソッド と時間 が表示され る
コードが見づらい部分も多いと思うので... https://github.com/Ryu-nakay/measuri ng-method-execution-time-macro.git コードを中心に説明をすると字が小さくて見づらいことが 想定されるので、文字中心で説明します〜!🙏 コードは必要に応じてGitHubをご覧ください → (スライドはイベント終了後に公開するので、その際に照ら し合わせながら見ていただくでも問題なし) 会場の様子を見ながら、必要そうであればライブコーディング風にお見せします
1. 単体のメソッドを計測可能にする
ルール: メソッドの実行時間の計測 メソッドの 処理開始時の時刻 と 処理終了時の時刻 の差を実行時間とする 11 終了時刻 開始時刻
実行時間 10時 20分 40秒 10時 20分 30秒 10秒 ざっくりとしたイメージ
ルール: メソッドの実行時間の計測 メソッドの 処理開始時の時刻 と 処理終了時の時刻 の差を実行時間とする 12 終了時刻 開始時刻
実行時間 10時 20分 40秒 10時 20分 30秒 10秒 ざっくりとしたイメージ メソッドの開始時刻と終了時刻を取得し、その差を 出力すればよさそう!
ルール: メソッドの実行時間の計測 -作成するMacroのイメージ- 13 展開 @自作Macro @自作Macro (今回、defer文などは考慮していません )
ルール: メソッドの実行時間の計測 -計測に使用する便利な型- 14 計測の事前準備として、MeasureTimeLoggerという型を作りました - 初期化時に時刻でプロパティを初期化 - stop呼び出しで実行時間の計算とprint出力
ルール: メソッドの実行時間の計測 -計測に使用する便利な型- 15 展開 BodyMacro を使ってメソッドの中身を書き換えよう!
2. BodyMacroを実装する
実装 -型の準備- BodyMacroに準拠した型を定義し、expansionメソッドを準備します // 実装
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) - expansionメソッドの引数 declaration が FunctionDeclSyntax型に変換できるかで判定する - FunctionDeclSyntax.body?.statements がメソッドの中身の構文となる
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける - 1.で取得した『メソッドの中身の構文』を 1行ずつ取り出し、その型が ReturnStmtSyntaxかどうか でreturn構文を判定することができる - 元の構文 + 処理終了時の構文となったものが出来上がる 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に `measureTimeLogger.stop()` を付け加える return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`を付け加 える
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`を付け加える - 2.で作成した『元のメソッドの構文 + メソッド終了時の構文』の先頭にメソッド開始時の構文を付け 加えてreturnする
最終的なBodyMacroの実装 https://github.com/Ryu-nakay/measuri ng-method-execution-time-macro.git
実装 あとは、Macroを使えるようにするために各所に記述を追加し ...
実装 無事に時間計測ができるようになりました!
Macro展開時 ↑ Macroを展開すると計測開始・終了の処理が付け加えられ ていることがわかります
一括でつけたい 無事に計測可能になったものの... 毎回メソッドに付与していくの面倒だなぁ... 一括で型のメソッド全てを計測可能にできないかな?
再掲: 完成イメージ 27 @(自作のMacro) 型に対して自作のMacroを付ける 型のメソッドを実行した時に、 実行したメソッド と時間 が表示され る
こうすればいける? 28 @(自作のMacro) Macroを展開 メソッド単体での計測はできるので、型に対してMacroをつけた時に右のように各 メソッドに @MeasureTimeが付与されるようにすればいいのでは?
3. MemberAttributeMacroを実装する
実装 -最終的なMemberAttributeMacroのコード- さっきと比べるとすごくシンプル!
実装 -最終的なMemberAttributeMacroのコード- expansionを実装 memberがメソッドの 構文であるかを判定 メソッドの構文であるものに対して @MeasureTimeを付与
実装 -最終的なMemberAttributeMacroのコード- expansionを実装 memberがメソッドの 構文であるかを判定 メソッドの構文であるものに対して @MeasureTimeを付与 これだけで完成!
実装 あとは、Macroを使えるようにするために各所に記述を追加し ...
使ってみる 34 Macroを展開 型に @TimeMeasureable を付けることで、その型が持つメソッドに @MeasureTimeを付与できました!
まとめ
まとめ・感想 36 まとめ • メソッド単体で計測可能することができる @MeasureTime を実装した ◦ BodyMacro •
型のメソッドに @MeasureTimeを付与できる @TimeMeasureableを実装した ◦ MemberAttributeMacro 感想 • 「Swift Macro / Swift Syntaxって専門知識がないと難しそう」と食わず嫌いしていたが、実際に 触ってみると動くものを作れるぐらいにはできた • Swift AST Explorer が便利すぎた ◦ Syntaxの深い知識を持ち合わせていなくても構造や型を調べられた • 本当は「Swiftのコードから実行された処理のシーケンス図を出力したい」というモチベーションで 始めたので、今後実現できたらと ...
働くをもっと楽しく、創造的に 37