SwiftData
で@Query
を使用してデータを取得する際に単純な全件取得ではなく、条件付きで取得したい場合に#Predicate
を使用します。
公式ドキュメント
Predicate | Apple Developer Documentation
全件取得の場合
import SwiftData
import SwiftUI
struct DailyTask {
let date: Date
}
struct ContentView: View {
@Query var dailyTasks: [DailyTask]
var body: some View {
VStack {
....
}
}
}
条件付き取得
実装例として「dateが今週のもの」を取得する処理を書いてみます
一旦公式ドキュメント通りに書いてみる
// 公式ドキュメントの実装例
let messagePredicate = #Predicate<Message> { message in
message.length < 100 && message.sender == "Jeremy"
}
// dateが今週のものを取得する
let pridicateDailyTask = #Predicate<DailyTask> { dailyTask in
let calendar = Calendar.current
let now = Date()
let startOfWeek = Calendar().date(from: Calendar().dateComponents([.yearForWeekOfYear, .weekOfYear], from: now))!
let endOfWeek = Calendar().date(byAdding: .day, value: 6, to: startOfWeek)!
return dailyTask.date >= startOfWeek && dailyTask.date <= endOfWeek
}
実際に書いてみると以下のエラーが表示されビルドが通りません。
Instance member 'pridicateDailyTask' cannot be used on type 'ContentView'; did you mean to use a value of this type instead?
解決策
static
をつけると実行できました
import SwiftData
import SwiftUI
struct DailyTask {
let date: Date
}
struct ContentView: View {
// staticをつける!!
static let pridicateDailyTask = #Predicate<DailyTask> { dailyTask in
let calendar = Calendar.current
let now = Date()
let startOfWeek = Calendar().date(from: Calendar().dateComponents([.yearForWeekOfYear, .weekOfYear], from: now))!
let endOfWeek = Calendar().date(byAdding: .day, value: 6, to: startOfWeek)!
return dailyTask.date >= startOfWeek && dailyTask.date <= endOfWeek
}
@Query(filter: pridicateDailyTask) var dailyTasks: [DailyTask]
var body: some View {
VStack {
....
}
}
}
functionで書きたい場合
引数で値を受け取りたかったり、可読性の観点からFunctionで書きたい場合はこんな感じです
import SwiftData
import SwiftUI
struct DailyTask {
let date: Date
}
struct ContentView: View {
@Query(filter: pridicateDailyTask()) var dailyTasks: [DailyTask]
var body: some View {
VStack {
....
}
}
// staticをつける!!
static func pridicateDailyTask() -> Predicate<DailyTask> {
let calendar = Calendar.current
let now = Date()
let startOfWeek = Calendar().date(from: Calendar().dateComponents([.yearForWeekOfYear, .weekOfYear], from: now))!
let endOfWeek = Calendar().date(byAdding: .day, value: 6, to: startOfWeek)!
return #Predicate<DailyTask>{ dailyTask in
dailyTask.date >= startOfWeek && dailyTask.date <= endOfWeek
}
}
}
最後に
不備、間違い等あればご指摘いただけると幸いです。