Avi Sabag
Avi Sabag

Reputation: 61

query with Fetch Request using CoreData on Swift

Sorry guys if there's already a thread about it but been stuck with it for a while.

I'm kinda new to CoreData(knows only how to persist and fetch items only) and I'm trying to do a little query in my app which will load only the ones with the isDone attribute = to "True".

the thing is I don't know how to use NSFetchRequest & NSPredicate so im kinda stuck, hope you guys can help me out with some tips <3, Here's my code:

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

Upvotes: 0

Views: 2019

Answers (3)

Avi Sabag
Avi Sabag

Reputation: 61

Yay fellas! I solved it, I splited it to two functions like this: thank you very much for your help ! <3 I've learned how to use CoreData :) much love!.

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

and then in the Sege for case 0(not done task) I loadTasks, and in case1 I load DoneTasks.

Upvotes: 0

PRSHL
PRSHL

Reputation: 1443

You can write queries like this

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
    }

And then you just fetch them with:

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

You also can add arguments etc. to your function and pass them in the FetchRequest

I can recommend this tutorial to understand the core concepts of coredata

Upvotes: 1

Reqven
Reqven

Reputation: 1778

You can use one of these

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

Upvotes: 1

Related Questions