iOS18に追加されたSwiftDataの新機能
WWDC24から時間がたってしまいましたが SwiftData 関連をまとめました。
この記事は『SwiftData を iOS アプリでためす』マガジンの最新記事です。
『SwiftData を iOS アプリでためす』マガジンで読める記事:
SwiftDataをシンプルにためす
CSVファイルデータを読みSwiftDataで使う
アプリ起動時の表示情報にSwiftDataを使う
マクロ と オブザベーション
SwiftDataの検索・絞り込みと並べ替え
iOS18に追加されたSwiftDataの新機能(この記事)
画像クリックで拡大表示できます
画像を拡大表示中は画像の左右をクリックで画像だけを順に表示できます
ソースコード部分は左右にスクロールできます
リンクしているドキュメントは英文が多いですが、翻訳機能を活用してください
公式資料
セッションビデオ
SwiftDataに関するWWDC24セッションビデオは3本あります。
現在どのビデオも日本語字幕付きで視聴できます。
Updatesページ
SwiftData updatesページ(英文)からアップデートしたドキュメントにリンクしています。
WWDC24セッションで紹介されたすべてが載っているわけではありません。
チュートリアル
Develop in Swift Tutorials に SwiftData のチュートリアルがありました。
英文ですが翻訳機能を利用できます。
Xcodeののダウンロードから始まる、SwiftUIを使ってSwift言語でアプリ開発する手順を体験できるチュートリアルです。
SwiftData を学ぶのは「SwiftUI foundations」の次にある「Data modeling」で、SwiftDataでデータを保存する方法と、Swift Testingでアプリが適切に機能することを確認する方法を学べます。
Xcode・Swift・SwiftUI・アプリ開発 のどれかにまだ不慣れな場合はこのチュートリアルの最初から読み進めるのがおすすめです。
解説記事と演習が交互に配置され学習効果の高そうなチュートリアルです。
解説記事からはドキュメントにもリンクしていて復習でも役立ちそうです。
Data modeling 最初の Welcome to data modeling から始めるとページの末尾に次ページへのリンクがあり順に進むことができます。
Chapter 1 NEW: Custom types and Swift Testing【参考所要時間1時間】
(NEW: カスタムタイプとスウィフトテスト)※(括弧内はSafariによる翻訳)
Welcome to data modeling (データモデリングへようこそ)
Model data with custom types (カスタムタイプでデータをモデル化する)
Wrap-up: Model data with custom types
(まとめ:カスタムタイプでデータをモデル化する)
Add functionality with Swift Testing (Swift Testingで機能を追加する)
Wrap-up: Custom types and Swift Testing
(まとめ:カスタムタイプとスウィフトテスト)
Chapter 2 Models and persistence【参考所要時間1.5時間】
(モデルと粘り強さ)
Save data (データを保存する)
Wrap-up: Models and persistence (まとめ:モデルと持続性)
Chapter 3 NEW: Navigation, editing, and relationships【参考所要時間3.5時間】
(新規:ナビゲーション、編集、および関係)
Navigate sample data (サンプルデータをナビゲートする)
Wrap-up: Navigate sample data (まとめ:サンプルデータをナビゲートする)
Create, update, and delete data (データの作成、更新、削除)
Wrap-up: Create, update, and delete data
(まとめ:データの作成、更新、削除)
Work with relationships (人間関係で働く)
Wrap-up: Navigation, editing, and relationships
(まとめ:ナビゲーション、編集、および関係)
Chapter 4 NEW: Observation and shareable data models【参考所要時間2時間】
(新規:観察と共有可能なデータモデル)
Complete a game with logic (論理でゲームを完了する)
Wrap-up: Observation and shareable data models
(まとめ:観察と共有可能なデータモデル)
Data modeling の第1章 NEW: Custom types and Swift Testing の最初の記事:
iOSではありませんが App Dev Tutorials にも SwiftData のチュートリアルがありました。(macOS の中にあります)
Persisting user data (永続ユーザーデータ)
Adding and deleting data (データの追加と削除)
Fetching, sorting, and filtering data
(データの取得, 並べ替え, フィルタリング)
の三つがあります。(括弧内はSafariによる翻訳)
アイコンからわかるように解説文のみです(プロジェクトはダウンロード可能です)
英文ですが翻訳機能を利用できます。
「SwiftDataの新機能」セッション
webとDeveloperアプリともにWWDC24セッションビデオの字幕は日本語に対応済みです。
webでのビデオ画面操作について「利用方法」からリンクしている「Apple Developerビデオを最大限に活用」に詳しく書かれています。
概要タブ
「概要」はweb・Developerアプリともにセッション概要を日本語で表示しています。
セッションタイトルも翻訳された「SwiftDataの新機能」だけが表示されます。
関連する章(チャプター)で注目部分の頭出しができます。
リソースでは関連するサンプルコード、フォーラムへのリンク、ドキュメントへのリンク、ビデオデータのダウンロードが可能です。
ビデオデータのダウンロードではmp4ファイルをダウンロードします。
オフラインで再生できますが、字幕データはありません。
関連ビデオへのリンクもあります。
トランスクリプトタブ
webでは「トランスクリプト」を選ぶと字幕テキストが表示されますが、Developerアプリの「字幕」タブでは日本語テキストが表示されます。
「トランスクリプト/字幕」のテキストをクリックすると対応するビデオ(その字幕を表示する部分)を再生します。
「トランスクリプト」(Developerアプリでは「字幕」)ビデオ全体の字幕をテキストで表示しコピーもできます。
webでは「トランスクリプト」タブで字幕表示の先頭の「ダウンロード」ボタンで全字幕をテキストファイルでダウンロードできます。
コードタブ
「コード」はビデオで解説しているコードをコピーして利用できます。
各コードのタイムスタンプまたはタイトルをクリックするとビデオの対応部分を再生します。
webではコードをスクロールするとビデオ画面もスクロールしてしまうので画面も同時に参照したい場合はピクチャーインピクチャー機能を利用すると良いでしょう。
webとDeveloperアプリの違い
webとDeveloperアプリでは字幕の表示がかなり違います。
Developerアプリで字幕タブにしている場合ビデオ再生中の字幕を強調し自動スクロールして表示し続けます。
「トランスクリプト/字幕」を検索できますが、webでは一致部分を一覧で表示します。
検索結果をクリックすると目的の部分を再生します。
検索の解除ボタンがありませんが、「トランスクリプト」または「コード」タブクリックで検索から抜けることができます。
翻訳した字幕テキストの検索なので検索結果は日本語字幕と英語字幕では異なります。
Developerアプリは⌘F(編集メニュー>検索…)で検索できますが、コードを表示していても「字幕タブ」に切り替わります。
なお検索中は「概要、字幕、コード」のタブは消え字幕全体の表示に切り替わります。
YouTubeのApple Developerチャンネル
今年のセッションビデオはYouTubeでも同時公開されました。
WWDC24セッションビデオのタイトルは主要なものは日本語に翻訳されたタイトルが表示されるようです。
「概要」にある情報は「もっと見る」クリックで表示できます。
文字起こしを表示すると字幕テキスト(英文)を確認できます。
YouTubeは自動翻訳機能があり、日本語字幕が提供される前でも日本語字幕で視聴できました。
「SwiftDataの新機能」ビデオの内容にそって詳しく確認しましょう。
#Uniqueマクロ
#Unique は iOS 18.0以降で利用可能になったマクロです。
ドキュメントでは Unique(_:) となっています。
値の重複をゆるさないプロパティをキーパスで指定するマクロです。
// Uniqueマクロの使用例(ドキュメントより)
@Model
final class Person {
// モデル定義の一部として、固有の制約を宣言します。
#Unique<Person>([\.id], [\.givenName, \.familyName])
var id: UUID
var givenName: String
var familyName: String
...
このようにキーパスの配列で指定します。
上記コードでは id は単独で一意、givenName と familyName は組み合わせで一意です。
つまり familyName は同じでも givenName が違えば独立したデータとして追加できます。
マクロなので Xcode 16 で展開(Expand Macro)を試しましたが展開結果は表示されませんでした。
@Attribute(.unique)と#Uniqueマクロの違い
SwiftDataでは登場当初からモデルのプロパティに @Attribute(.unique) で一意にすることができました。
#Uniqueマクロは単独のプロパティはもちろん、複合制約(プロパティの組み合わせ)も指定できます。
セッションビデオでは旅行データの名前・開始日・終了日の組み合わせを一意にしていました。
@Attribute(.unique)のドキュメントについては「CSVファイルデータを読みSwiftDataで使う」に書きました。
すでにある名前・開始日・終了日の組み合わせで新しいデータを追加しようとすると、古い内容は上書きされます。
履歴API
SwiftDataの新機能である履歴機能を使うと 挿入・更新・削除されたモデルを時間の経過とともにアプリで把握できます。
@Attribute(.preserveValueOnDeletion)
モデルが削除されると 保存するように指定された値は トゥームストーン(墓石)値として履歴情報に保持され、これらの変更を処理するために必要な情報がアプリに提供されます。
履歴機能の詳細は 「SwiftDataの履歴機能によるモデル変更のトラッキング(Track model changes with SwiftData history)」セッションで解説されています。
なおこのセッションの日本語タイトルは当初「SwiftDataの履歴でモデルの変更を追跡」となっていましたが現在は変更されています。
カスタムデータストア
今回SwiftDataの新機能としてデフォルト(CoreData)以外のデータストアをSwiftDataで利用する方法が提供されました。
model containerの保存先の指定などはこれまでも可能でした。
永続化データurlの指定については「アプリ起動時の表示情報にSwiftDataを使う」に書きました。
新機能で独自のデータストアを利用可能になりました。
(アプリ開発で独自のデータストアが必要な場合は多くはなさそうですが)
「SwiftDataを使用したカスタムデータストアの作成(Create a custom data store with SwiftData)」セッションを参照してください。
このセッションの日本語タイトルも当初の「SwiftDataでカスタムデータストアを作成する」から変更されています。
Xcodeプレビュー
Xcode プレビューで使用するカスタムコンテナも利用可能になりました。
ビデオで紹介されたコード:
struct SampleData: PreviewModifier {
static func makeSharedContext() throws -> ModelContainer {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(for: Trip.self, configurations: config)
Trip.makeSampleTrips(in: container)
return container
}
func body(content: Content, context: ModelContainer) -> some View {
content.modelContainer(context)
}
}
extension PreviewTrait where T == Preview.ViewTraits {
@MainActor static var sampleData: Self = .modifier(SampleData())
}
PreviewModifier
プレビューが表示される環境を定義するタイプのプロトコルです。
PreviewModifierのドキュメント
このドキュメントのサンプルは extension PreviewTrait を使っていないのでビデオで紹介されたコードよりはややシンプルです。
makeSharedContext()のドキュメント
当初 https://developer.apple.com/documentation/swiftui/previewmodifier/makesharedcontext()-2nmhp をみつけましたが、現在はリンクが切れています。
modelContainer(_:)のドキュメント
このビューの環境で、モデルコンテナと関連するモデルコンテキストを設定します。
modelContainer(_:) は WindowGroup に対して適用するmodifier(_:) と同じ形式ですが Scene ではなく some View を返します。
modifier(_:)のドキュメント
PreviewModifier をアタッチします。
@Previewable
動的なプロパティをプレビューにインラインで表示できるようにするマクロです。
// Create a preview query using @Previewable
import SwiftUI
import SwiftData
#Preview(traits: .sampleData) {
@Previewable @Query var trips: [Trip]
BucketListItemView(trip: trips.first)
}
#Preview のロージャの外で @Previewable を使用することはできません。
カスタマイズクエリ
検索を例にカスタマイズクエリを説明しています。
// Create a Predicate to find a Trip based on Search Text
let predicate = #Predicate<Trip> {
searchText.isEmpty ? true : $0.name.localizedStandardContains(searchText)
}
searchText で name を検索する例です。
localizedStandardContains(_:) を使って name に searchText が含まれていれば検索結果として表示させる部分です。
この部分は従来からの使い方で、「SwiftDataの検索・絞り込みと並べ替え」でも独自のサンプルコードと共に説明しています。
#Expressionマクロ
このマクロのドキュメントも見つけられていません。
#Expressionマクロは SwiftData ではなく Foundation フレームワークのようです。
#Predicateマクロは true または false を返すシンプルな条件ですが、#Expressionマクロではより複雑な評価が可能になります。
#Indexマクロ
#Indexマクロでクリエを高速で効率良く行うことが可能になります。
webとDeveloperアプリともに #Indexマクロ に対応するコード(「コード」タブの最後のスニペット)の行末が複数行切れているようです。
// 12:41 - Add Index for commonly used KeyPaths or combination of KeyPaths
// Add Index for commonly used KeyPaths or combination of KeyPaths
import SwiftData
@Model
class Trip {
#Unique<Trip>([\.name, \.startDate, \.endDate
#Index<Trip>([\.name], [\.startDate], [\.endDate], [\.name, \.startDate, \.endDate])
var name: String
var destination: String
var startDate: Date
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem
var livingAccommodation: LivingAccommodation
}
ビデオ画面では
// Add Index for commonly used KeyPaths or combination of KeyPaths
import SwiftData
@Model
class Trip {
#Unique<Trip>([\.name, \.startDate, \.endDate])
#Index<Trip>([\.name], [\.startDate], [\.endDate], [\.name, \.startDate, \.endDate])
var name: String
var destination: String
var startDate: Date
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem]()
var livingAccommodation: LivingAccommodation?
}
一般的にインデックスで高速・効率化する場合トレードオフとしてメモリまたはストレージを多く消費します。
インデックスを保存する領域と保存処理の処理時間が発生するのでデータ追加時にパフォーマンスが落ちないかストレージはどの程度大きくなるか実際の規模のデータで確認するのが良さそうです。
#Indexマクロは SwiftData updates ページからリンクしているドキュメントがあります。
最後に
WWDC23で登場した SwiftData は WWDC24 でどう発展するのか注目していましたが、項目数も中身も「これだけ?」が第一印象でした。
ドキュメントの充実も期待しましたが WWDC24 後も進んでいるとは言えません、しかしチュートリアルの登場は朗報です。
単純に SwiftData が CoreData 以外にも対応できるようになっただけではなく「CoreData との密接な結合が解除され、広範囲にわたる抽象化と分割が行われた」とすると今後の展開が楽しみです。
ここから先は
SwiftData を iOS アプリでためす
新しい SwiftData SDK の日本語情報です。
今後も記事を増やすつもりです。 サポートしていただけると大変はげみになります。