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
190
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
Health Kit × Foundation Models でAIコーチを作ってみた
ryunakayama
0
82
iOSの画面の状態のアレコレを調査してみた
ryunakayama
0
38
作文ツール(Writing Tools)をアプリから制御する
ryunakayama
0
33
iOSアプリで測る!名古屋駅までの 方向と距離
ryunakayama
0
230
「ジェン文字」をアプリ内で使ってみよう
ryunakayama
0
100
SwiftDataと連携したWidgetを作ってみた
ryunakayama
1
130
Appleの審査担当の方とお話ししてみた!
ryunakayama
0
280
大公開!iOS開発の悩みトップ5 〜iOSDC Japan 2024〜
ryunakayama
0
350
Translation API について 〜WWDC24〜
ryunakayama
0
350
Other Decks in Programming
See All in Programming
Devvox Belgium - Agentic AI Patterns
kdubois
1
150
スキーマ駆動で、Zod OpenAPI Honoによる、API開発するために、Hono Takibiというライブラリを作っている
nakita628
0
320
CSC305 Lecture 11
javiergs
PRO
0
270
マンガアプリViewerの大画面対応を考える
kk__777
0
260
CSC305 Lecture 10
javiergs
PRO
0
260
他言語経験者が Golangci-lint を最初のコーディングメンターにした話 / How Golangci-lint Became My First Coding Mentor: A Story from a Polyglot Programmer
uma31
0
420
monorepo の Go テストをはやくした〜い!~最小の依存解決への道のり~ / faster-testing-of-monorepos
convto
2
550
実践Claude Code:20の失敗から学ぶAIペアプログラミング
takedatakashi
18
8.7k
開発組織の戦略的な役割と 設計スキル向上の効果
masuda220
PRO
9
1.6k
品質ワークショップをやってみた
nealle
0
640
テーブル定義書の構造化抽出して、生成AIでDWH分析を試してみた / devio2025tokyo
kasacchiful
0
300
チームの境界をブチ抜いていけ
tokai235
0
220
Featured
See All Featured
A Modern Web Designer's Workflow
chriscoyier
697
190k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
130k
Optimizing for Happiness
mojombo
379
70k
Making Projects Easy
brettharned
120
6.4k
Site-Speed That Sticks
csswizardry
13
930
Why Our Code Smells
bkeepers
PRO
340
57k
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.9k
Building a Scalable Design System with Sketch
lauravandoore
463
33k
Building an army of robots
kneath
305
46k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
23
1.5k
The Language of Interfaces
destraynor
162
25k
Java REST API Framework Comparison - PWX 2021
mraible
34
8.9k
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