在 Swift 上使用 CoreData 使用 Fetch Request 进行查询

Posted

技术标签:

【中文标题】在 Swift 上使用 CoreData 使用 Fetch Request 进行查询【英文标题】:query with Fetch Request using CoreData on Swift 【发布时间】:2020-07-31 08:28:38 【问题描述】:

对不起,如果已经有一个关于它的线程但被卡住了一段时间。

我对 CoreData 有点陌生(只知道如何持久化和获取项目),我正在尝试在我的应用程序中进行一个小查询,该查询将仅加载具有 isDone 属性 =“True”的那些。

问题是我不知道如何使用 NSFetchRequest 和 NSPredicate 所以我有点卡住了,希望你们能帮助我一些提示

import Foundation
import CoreData
import UIKit
import SwipeCellKit

class TasksManViewController: UITableViewController, SwipeTableViewCellDelegate 
    
    
    
    @IBOutlet weak var Sege: UISegmentedControl!
    
    let isSwipeRightEnabled = true
    
    
    var tasksArray = [Task]()
        didSet 
            // because we perform this operation on the main thread, it is safe
            DispatchQueue.main.async 
                self.tableView.reloadData()
            
        
    
    
    var doneTasksArr = [Task]() // an array of what to disply.
    
    
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    
    override func viewDidLoad() 
        
    
    
    
    override func viewWillAppear(_ animated: Bool) 
        loadTasks()
    

    
    
    // MARK: - DataSource + Delegate Methods:
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return tasksArray.count
    
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "taskCellRow") as! SwipeTableViewCell
        cell.delegate = self
        
        cell.textLabel?.text = tasksArray[indexPath.row].title
        
        return cell
    
    
    
    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? 
        if orientation == .left 
            guard isSwipeRightEnabled else  return nil 
            let doneAction = SwipeAction(style: .destructive, title: "Done")  (action, indexPath) in
                
                //STEP1: Append the task to the doneTasksArr:
                self.tasksArray[indexPath.row].isDone = true
                self.doneTasksArr.append(self.tasksArray[indexPath.row])
                
                
                //STEP2: Delete the task from the tasksArray since it was done.
                self.context.delete(self.tasksArray[indexPath.row])
                
                //STEP3: Remove the Row:
                self.tasksArray.remove(at: indexPath.row)
                
                //STEP4: Update the Model:
                self.saveTasks()
                
                

                self.tableView.reloadData()

                
                
                
            
            
            
            //configure btn:
            doneAction.backgroundColor = .cyan
            
            return [doneAction]
            
         else 
            let deleteAction = SwipeAction(style: .destructive, title: "Delete")  action, indexPath in
                
                self.context.delete(self.tasksArray[indexPath.row])
                
                self.tasksArray.remove(at: indexPath.row)
                
                
                self.saveTasks()
                
                self.tableView.reloadData()
                
            
            
            return [deleteAction]
        
        
    
    
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        tableView.deselectRow(at: indexPath, animated: true)
        
        
    
    
    // MARK: - Class Methods:
    @IBAction func addBtnTapped(_ sender: UIBarButtonItem) 
        
        insertNewTask()
        
    
    
    
    
    func insertNewTask() 
        var textField = UITextField()
        
        
        let alert = UIAlertController(title: "New Task", message: "Please Add Your Task", preferredStyle: .alert)
        
        alert.addTextField  (alertTextField) in
            alertTextField.placeholder = "Create New Task"
            textField = alertTextField
        
        
        
        let action = UIAlertAction(title: "Add", style: .default)  (action) in
            let newItem = Task(context: self.context)
            
            newItem.title = textField.text!
            newItem.isDone = false
            
            
            self.tasksArray.append(newItem)

            self.saveTasks()
            
            self.tableView.reloadData()

        
        
        
        
        alert.addAction(action)
        
        
        
        self.present(alert, animated: true, completion: nil)
        
    
    
    
    
    // MARK: - Sege Section:
    @IBAction func segeControlTapped(_ sender: UISegmentedControl) 
        
        switch Sege.selectedSegmentIndex
        
        case 0:
            //Loading normal tasks which not done
            loadTasks()
            
        case 1:
            //Loading the doneTasks:
            loadDoneTasksFrom()

            
        default:
            print("There's something wrong with Sege!")
        
        
        tableView.reloadData()
    
    
    
    //MARK: - Model Manipulation Methods:
    func saveTasks() 
        do 
            try! context.save()
         catch 
            print("Error Saving context \(error)")
        
    
    
    func loadTasks() 
        let request: NSFetchRequest<Task> = Task.fetchRequest()
        do
            tasksArray = try! context.fetch(request)
         catch 
            print("There was an error with loading items \(error)")
        
    
    
    
    
    func loadDoneTasksFrom() 
        let request: NSFetchRequest<Task> = Task.fetchRequest()
        
        request.predicate = NSPredicate(format: "isDone == %@", "true")
        
        request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
        
        do
            tasksArray = try context.fetch(request)
         catch 
            print("Error fetching data from context\(error)")
        
        
        tableView.reloadData()
        
    
    
    
    
    

    
    
    

【问题讨论】:

【参考方案1】:

您可以使用其中一种

NSPredicate(format: "isDone == %@", NSNumber(value: true))
NSPredicate(format: "isDone = %d", true)

【讨论】:

你的意思是在我的方法中使用它?【参考方案2】:

你可以这样写查询

static func getDoneTasks() -> NSFetchRequest<Task> 
        let request:NSFetchRequest<Task> = Task.fetchRequest() as! NSFetchRequest<Task>

        let sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: false)

        request.sortDescriptors = [sortDescriptor]
        let isDone = true
        request.predicate = NSPredicate(format: "isDone == %@", isDone)
        return request
    

然后您只需使用以下命令获取它们:

@FetchRequest(fetchRequest: Task.getDoneTasks()) var doneTasks: FetchedResults<Task>

您还可以在函数中添加参数等并将它们传递到FetchRequest

可以推荐this教程了解coredata的核心概念

【讨论】:

出于某种原因,它说“模糊使用 'fetchRequest()'” 一旦我实现了这个方法:|顺便说一句,@FetchRequest 据我所知适用于 SwiftUI 谢谢你,我一直在努力解决@FetchRequest NSSortDescriptors - 这已经解决了它和一个谓词 - 玩得很好 10/10【参考方案3】:

耶,伙计们!我解决了,我把它分成了两个这样的功能:非常感谢你的帮助!

func loadTasks() 
        let request: NSFetchRequest<Task> = Task.fetchRequest()
        
        request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: false))
        
        request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
        
        do
            tasksArray = try! context.fetch(request)
         catch 
            print("There was an error with loading items \(error)")
        
        
        tableView.reloadData()

    
    
    
    func loadDoneTasksFrom() 
        let request:NSFetchRequest<Task> = Task.fetchRequest()

        request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: true))
        
        request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
        
        do
            tasksArray = try context.fetch(request)
         catch 
            print("Error fetching data from context\(error)")
        
        
        tableView.reloadData()
        
    

然后在案例 0(未完成任务)的 Sege 中加载任务,在案例 1 中加载 DoneTasks。

【讨论】:

以上是关于在 Swift 上使用 CoreData 使用 Fetch Request 进行查询的主要内容,如果未能解决你的问题,请参考以下文章

Swift 2:使用两个 CoreData 实体填充 TableView

swift3.0 coredata 的使用

Swift CoreData:无法在 NSManagedObject 上调用指定的初始化程序

Swift:CoreData NSManagedObject 的自定义设置器

测试与非测试中的 Swift 和 CoreData Casting 问题

在 Swift 中使用 NSPredicate 对 CoreData 结果进行排序