1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftDataで@Queryを条件付き取得にする

Posted at

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
      }
    }
}

最後に

不備、間違い等あればご指摘いただけると幸いです。

参考記事

Swift #Predicate with function usage on the argument

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?