SwiftDataを使ってみた感想

Swift

はじめに

ソフトウェアエンジニアのTatsunoriです。
個人開発でサブスクリプションを管理するアプリを作っています。
今までだとローカルデータはRealmを使用していましたが、Appleから新しくSwiftDataが使えるようになったので、使用してみた感想になります。

結論

個人的にはRealmよりも使いやすくていいと思います。
これからアプリ開発でローカルDBを使用するならSwiftDataを選択します。

開発環境

  • Swift5
  • Xcode15.2
  • iOS17.2

メリット

プリミティブ型以外も使用できる

リファレンス

By default, SwiftData includes all noncomputed properties of a class as long as they use compatible types. The framework supports primitive types such as Bool, Int, and String, as well as complex value types such as structures, enumerations, and other value types that conform to the Codable protocol.

リファレンスにも記載ありますが、Cpdableを継承すればstructureでもenumerationでも保存できます。

@Model
final class Subscription {
    var color: ColorComponents
}

struct ColorComponents: Codable {
    let red: Float
    let green: Float
    let blue: Float

    var color: Color {
        Color(red: Double(red), green: Double(green), blue: Double(blue))
    }

    static func fromColor(_ color: Color) -> ColorComponents {
        let resolved = color.resolve(in: EnvironmentValues())
        return ColorComponents(
            red: resolved.red,
            green: resolved.green,
            blue: resolved.blue
        )
    }
}

上記サンプルのようにColorComponetsとしてユーザが選択した色をstructとしてSwiftDataに保存可能です。
プリミティブ型に変換して出し入れする必要がないので、変換コードを書く必要がなくシンプルになっていいです。

Widgetと共有するのにApp GroupのURLを設定しなくてもいい

Realmだとインスタンス作成する際に、Wiegetでも共有で使用するにはApp GroupのURLをConfigureationに設定する必要がありますが、
SwiftDataではそんな必要はないので、初めてApp Groupを使ってWidgetとDBを共有する際にアプリ側で保存したデータにWidget側でアクセスできない問題が回避できていいかなと思いました。

    public static var previewModelContainer: ModelContainer = {
        let schema = Schema([
            Subscription.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)

        do {
            let container = try ModelContainer(for: schema, configurations: [modelConfiguration])

            loadPreviewData().forEach { subscription in
                container.mainContext.insert(subscription)
            }

            return container
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

デメリット

Realm Studioが使えない

Realmを使った場合、シュミレータに保存したDBのデータを確認する際にRealm studioが使えますが、SwiftDataでは使いないです。
UIが見やすくて気に入っていたので残念です。代わりにDB Browser for SQLiteが使用できます。

Widget Previewでは.modelContainerが使えない

使えないないようです。

@Model
final class Subscription {
    var name: String
    ...
}

@MainActor
class DataContainer {
    public static func loadPreviewData() -> [Subscription] {
        let subscriptions: [Subscription] = [
            .init(name: "Apple music")
        }
    }
}

#Preview(as: .systemSmall) {
    StarshipWidget()
} timeline: {
    SimpleEntry(date: .now, configuration: .smiley, subscriptions: DataContainer.loadPreviewData())
}

だからといって上記のようにmodelContainerなしで@Modelの付いたModelを呼び出すとCanvasでエラーがでます。


    public static func fetchPreviewSubscriptions() -> [Subscription] {
        let context = DataContainer.previewModelContainer.mainContext
        let subscriptions = try? context.fetch(FetchDescriptor<Subscription>())
        return subscriptions ?? []
    }

#Preview(as: .systemSmall) {
    StarshipWidget()
} timeline: {
    SimpleEntry(date: .now, configuration: .smiley, subscriptions: DataContainer.fetchPreviewSubscriptions())
}

WidgetではmodelContainerからfetchでデータ取得する必要があるみたいです。

おわりに

まだ使用し始めたところですが、RealmよりSwiftUIと親和性が高く、CoreDataやSQLiteよりも使いやすく感じます。
これからいろいろと使ってみたいと思います。

参考

https://developer.apple.com/xcode/swiftdata/
https://developer.apple.com/documentation/swiftdata
https://developer.apple.com/videos/play/wwdc2023/10187/

コメント

タイトルとURLをコピーしました