WWDC Quick Look 💓 By SwiftGGTeam
What's new in Foundation

What's new in Foundation

元の動画を見る

ハイライト

Foundation は Locale を参照型から値型へ変更し、#Predicate マクロによって述語クエリのプロパティ名と型チェックをコンパイル時に行えるようになりました。


主要内容

今回の Foundation アップデートのメインテーマは、Objective-C 時代から残っていた設計上の負債を一つひとつ返済していくことです。Locale を参照型から値型へ変更したというのは、一見すると内部実装の細部に過ぎないように思えますが、これによってマルチスレッド由来のバグを一群まるごと潰すことができます。たとえば、ユーザーがシステム言語を切り替えた瞬間に 2 つのスレッドが異なる locale を読み取り、フォーマット結果が一致しなくなる、といった類のバグです。この種の問題は再現が極めて難しく、これまではロックを掛けるか、あるいは祈るくらいしか回避策がありませんでした。今回の変更で Locale.current は呼び出し時点のスナップショットを返すようになり、一度手元に取得した値が後から書き換わる心配はありません。

JSONEncoder および JSONDecoder の内部実装も書き直され、パフォーマンスが向上しています。大量の API レスポンスを処理するアプリにとっては、何もしなくても得られる嬉しい改善でしょう。もう一つ実用的な変更として OutputFormatting.withoutEscapingSlashes が追加され、/ のエスケープ挙動を制御できるようになりました。バックエンドによっては \/ の扱いが長らく地雷になっていたため、これは地味ながら助かるアップデートです。

#Predicate マクロは今回の目玉です。NSPredicate では "age >= 18" のような文字列でクエリを書くため、タイポは実行時にしか判明しませんでした。一方 #Predicate を使えば、Swift コンパイラがビルド時にプロパティ名と型をチェックしてくれます。SortDescriptor のチェーン可能な API と組み合わせることで、Core Data クエリもようやくエンドツーエンドで型安全に書けるようになりました。


詳細

#Predicate は文字列ベースのクエリを Swift クロージャに変換し、型チェックをコンパイラに任せます。典型的な使い方は次のとおりです。

struct Person {
    var name: String
    var age: Int
}

let adults = #Predicate<Person> { person in
    person.age >= 18
}

let sortByName = SortDescriptor(\Person.name)

ポイント:

  • #Predicate<Person> は述語を Person 型に紐付け、クロージャ引数 person のフィールドアクセスがコンパイラによって検査されます。
  • person.age >= 18 はそのまま Swift の式なので、プロパティ名を間違えれば Xcode が即座にエラーを出します。実行時に文字列をパースする際の落とし穴も避けられます。
  • SortDescriptor(\Person.name) は KeyPath でソートフィールドを指定するため、従来の文字列キーによるタイポを防げます。
  • この述語は SwiftData や Core Data の FetchDescriptor に渡せるため、エンドツーエンドで型安全になります。

JSONEncoder の出力制御は outputFormatting オプションを組み合わせて指定できます。

let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes]

ポイント:

  • .prettyPrinted を指定すると出力にインデントが付き、デバッグしやすくなります。
  • .withoutEscapingSlashes を指定すると / のエスケープが無効化され、http:\/\/example.com ではなく http://example.com がそのまま出力されます。
  • 両者は OptionSet 構文で組み合わせ可能で、互いに干渉しません。

重要ポイント

  • やること: プロジェクト内の Locale.current 呼び出しを一通り棚卸しする。

    • 価値: マルチスレッド環境下での locale ドリフトによるフォーマット崩れは再現が極めて困難で、本番障害の温床になりがちです。
    • 始め方: Xcode の Find Navigator で Locale.current をプロジェクト全体検索し、特に GCD キューや async コンテキスト内での使用箇所を重点的にチェックしましょう。
  • やること: 新規コードの NSPredicate 文字列を #Predicate マクロに移行する。

    • 価値: コンパイル時チェックによってタイポや型不一致の大半を未然に防ぎ、本番クラッシュを減らせます。
    • 始め方: まずは新しく追加するクエリロジックから着手し、関連モジュールに手を入れるタイミングで既存コードを少しずつ移行していくのがおすすめです。
  • やること: デプロイメントターゲットを上げた後、JSON パースのパフォーマンスベースラインを取り直す。

    • 価値: JSONEncoder / JSONDecoder の内部書き直しはコード変更なしで恩恵が得られる、いわばタダ乗りの最適化です。
    • 始め方: XCTest の measure ブロックで大規模 JSON ペイロードのベンチマークを取り、アップデート前後の所要時間を比較しましょう。

関連セッション

コメント

GitHub Issues · utterances