🙌
SwiftDataをSwiftUIから分離する
きっかけ
SwiftDataをSwiftUIから分離したかった。
SwiftUIとセットの運用する記事はたくさん出てきたけど、分離する情報はあんまり無かったので、調べたことをここにまとめておきます
やりたいこと
- 今まで使っていたローカルDBをRealmからSwiftDataに移行したい。
- 使用する環境はPresenter経由で呼び出す(Viewから直接呼び出さない)
Modelクラスを準備する
この辺はどの方法でも変わらない。
まず保存したいクラスに @Model
マクロをつけてSwiftDataで扱えるモデルとして定義する
ContentData.swift
@Model
class ContentData {
let contentId: String
let imageData: Data
var text: String
init(
contentId: String,
imageData: Data,
text: String
) {
self.contentId = contentId
self.imageData = imageData
self.text = text
}
}
I/Oクラス
SwiftDataをimportし、ModelContainer
プロパティを生成する
ContentsRepository.swift
import SwiftData
@MainActor
struct ContentsRepository {
var container: ModelContainer?
init() {
self.container = try? ModelContainer(for: ContentData.self)
}
...
}
CRUD処理
Create
ContentsRepository.swift
func append(with content: ContentData) async {
container?.mainContext.insert(content)
}
READ
ContentsRepository.swift
func fetchAll() async -> [ContentData] {
var result = [ContentData]()
let descriptor = FetchDescriptor<ContentData>(sortBy: [SortDescriptor<ContentData>()])
do {
result = try container?.mainContext.fetch(descriptor) ?? []
} catch {
print(error)
}
return result
}
UPDATE
ContentsRepository.swift
func update(content: ContentData, with text: String) async {
let descriptor = FetchDescriptor<ContentData>(sortBy: [SortDescriptor<ContentData>()])
let list = (try? container?.mainContext.fetch(descriptor)) ?? []
let target = list.first(where: { $0.contentId == content.contentId })
target?.text = text
}
DELETE
ContentsRepository.swift
func delete(content: ContentData) async {
let descriptor = FetchDescriptor<ContentData>(sortBy: [SortDescriptor<ContentData>()])
let list = (try? container?.mainContext.fetch(descriptor)) ?? []
guard let target = list.first(where: { $0.contentId == content.contentId }) else { return }
container?.mainContext.delete(target)
}
まとめ
とりあえず、これだけでI/Oできるようになります。
今回のコードはGistでこちらにまとめておきました。
ModelContainer
の生成のところに気をつければ特に問題なくスムーズに扱うことができますが、Descriptorから対象のデータを抽出する方法はもっと良い方法が有る気がします🤨
Discussion