axiom-swift-modern について
古い API や生成コードでよく見られるパターンを、現代的な API、構文、並行処理の実践に置き換える Swift 開発スキルです。Swift コードの作成やレビュー向けに、エッジケースと安全な既定方針を示します。
主な機能
- 01Foundation の現代的な API への置き換え
- 02簡潔な Swift 構文の案内
- 03SwiftUI 便利 API の指針
- 04Swift 6.3 の並行処理の既定方針
- 05危険な回避策を避けるための指針
活用シーン
- 01古い API を使うコードの更新
- 02生成された Swift の古いパターンの確認
- 03並行処理と Actor 分離方式の選択
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-swift-modernインストール後、Claude Code で/axiom-swift-modernを入力して読み込まれたか確認します。
詳細
モダンな Swift のイディオム
目的
Claude は、トレーニングデータに含まれる古い Swift のパターンを頻繁に生成します。このスキルでは、最もよくあるパターンを修正します。コンパイルは問題なく通るものの、より明確で、効率的、または適切な最新の代替手段があるのに、古い API を使っているパターンです。
考え方:「LLM がすでに知っていることを繰り返さず、エッジケース、意外な点、非推奨への移行過程に注目する。」(Paul Hudson)
モダンな API への置き換え
| 古いパターン | モダンな Swift | 対応バージョン | 理由 |
|---|---|---|---|
Date() | Date.now | 5.6 | 意図がより明確です |
filter { }.count | count(where:) | 5.0 | 1 回の処理で済み、中間の割り当てがありません |
replacingOccurrences(of:with:) | replacing(_:with:) | 5.7 | Swift ネイティブで、Foundation とのブリッジが不要です |
CGFloat | Double | 5.5 | 暗黙のブリッジが可能です。例外:オプショナル、inout、Objective-C とのブリッジが必要な API |
Task.sleep(nanoseconds:) | Task.sleep(for: .seconds(1)) | 5.7 | 型安全な Duration API です |
DateFormatter() | .formatted() / FormatStyle | 5.5 | インスタンス管理が不要で、デフォルトでローカライズされます |
String(format: "%.2f", val) | val.formatted(.number.precision(.fractionLength(2))) | 5.5 | 型安全で、ローカライズされます |
localizedCaseInsensitiveContains() | localizedStandardContains() | 5.0 | ダイアクリティカルマーク、合字、文字幅の異なる文字に対応します |
"\(firstName) \(lastName)" | .formatted() を使った PersonNameComponents | 5.5 | ロケールに応じた名前の順序に対応します |
DateFormatter で使う "yyyy-MM-dd" | try Date(string, strategy: .iso8601) | 5.6 | モダンな解析方法です(エラーをスローします)。表示には "yyyy" ではなく "y" を使います |
ユーザー入力に対する contains() | localizedStandardContains() | 5.0 | 正しいテキスト検索・フィルタリングに必要です |
モダンな構文
| 古いパターン | モダンな Swift | 対応バージョン |
|---|---|---|
if let value = value { | if let value { | 5.7 |
単一式での明示的な return | return を省略します。if/switch は式です | 5.9 |
モディファイア内の Circle() | .circle(静的メンバー検索) | 5.5 |
import SwiftUI と併せた import UIKit | 多くの場合不要です。SwiftUI はほとんどの UIKit/AppKit 型を再エクスポートします。UIKit 専用の API(UIApplication など)を使う場合は残します | 5.5 |
Foundation のモダナイゼーション
| 古いパターン | モダンな Foundation | 対応バージョン |
|---|---|---|
FileManager.default.urls(for: .documentDirectory, ...) | URL.documentsDirectory | 5.7 |
url.appendingPathComponent("file") | url.appending(path: "file") | 5.7 |
books.sorted { $0.author < $1.author }(繰り返し使用) | Comparable に準拠させ、.sorted() を呼び出します | — |
表示用の日付形式における "yyyy" | "y" — すべての暦体系で正しく表示されます | — |
Claude が見落としがちな SwiftUI の便利な API
ContentUnavailableView.search(text: searchText)(iOS 17 以降)は検索語を自動的に含めるため、カスタム文字列を組み立てる必要はありません- フォーム内の
LabeledContent(iOS 16 以降)は、手動で HStack のレイアウトを組まなくても、ラベルの配置を統一できます confirmationDialog()は、トリガーとなる UI に付ける必要があります。Liquid Glass のモーフィングアニメーションは、ソース要素に依存します
Swift 6.3 の並行処理方針
Swift 5 時代のコードではなく、Swift 6.3 を前提としたコードを書いてください。これらのデフォルトは、並行処理のエラーが発生したときだけでなく、新しく書く Swift コードすべてに適用されます。
| デフォルト | 理由 |
|---|---|
| アプリ/UI モジュールでは、厳密な並行処理と MainActor によるデフォルトの隔離を前提とする | Swift 6.3 の言語モード。新規プロジェクトでは Xcode 26 以降のデフォルトです |
| GCD、DispatchGroup、コールバックの多重ネストよりも async/await を優先する | GCD はレガシー API を橋渡しするパターンであり、デフォルトのアーキテクチャではありません |
Async はバックグラウンド実行を意味しません。メインスレッド外での実行を強制するには @concurrent(Swift 6.2 以降)を使う | Async 関数は、呼び出し元と同じアクター上で再開されます |
非構造化の Task {} より、構造化並行処理(async let、TaskGroup)を優先する | 構造化タスクではキャンセルとエラーが自動的に伝播します |
明確な理由を示せない限り、Task.detached は使わない | アクターのコンテキスト、優先度、タスクローカル値が失われます |
| アクター境界を越えるデータには、Sendable な構造体/列挙型を優先する | 値型は本質的に安全に共有できます |
| アクターは、並行処理ドメイン間で本当に共有される可変状態にのみ使う | すべてのクラスをアクターにしないでください。UI コードは @MainActor のままにします |
@unchecked Sendable、@preconcurrency、nonisolated(unsafe) は一時的な橋渡しの手段として扱う | それぞれ削除チケットを設け、恒久的な手段にしないでください |
| コンパイラーエラーを黙らせるためだけに回避策を追加しない | 本番環境でクラッシュにつながるデータ競合を隠してしまいます |
詳しいパターン、判断ツリー、エラーごとのガイダンスについては、axiom-swift-concurrency を参照してください。
Claude がよく起こす幻覚
Claude が生成するコードでは、次のパターンがよく見られます。
DateFormatterのインスタンスをインラインで作成する — 代わりに.formatted()またはFormatStyleを使ってください。フォーマッターが必要な場合は、static letにしてください。DispatchQueue.main.asyncを使う — 代わりに@MainActorまたはMainActor.runを使ってください。GCD は橋渡しのパターンであり、デフォルトではありません。- バックグラウンド処理に
DispatchQueue.global().asyncを使う — 代わりに@concurrent(Swift 6.2 以降)を使うか、アクターに切り出してください。 - 「バックグラウンドで実行する」ために
Task.detachedを使う — 代わりに@concurrentを使ってください。Task.detachedではアクターのコンテキストが失われます。 - SwiftUI のパラメーターに
CGFloatを使う — Swift 5.5 以降では暗黙のブリッジにより、どこでもDoubleが使えます。 guard let x = x elseを生成する — 代わりに省略形のguard let x elseを使ってください。- 単一式の計算プロパティで明示的に値を返す —
returnを省略してください。 - ループ内で非構造化の
Task {}を生成する — 動的な並列処理にはTaskGroupを使ってください。 - 警告を黙らせるために
@unchecked Sendableを追加する — アクターまたは適切な Sendable 型に変更してください。
リソース
スキル: axiom-swift-performance、axiom-swift-concurrency、axiom-swiftui-architecture
コメント
Markdown 対応