0

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

3 Answers 3

1

You can use one of these

NSPredicate(format: "isDone == %@", NSNumber(value: true))
NSPredicate(format: "isDone = %d", true)
Sign up to request clarification or add additional context in comments.

1 Comment

u mean to use that inside my method?
1

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

3 Comments

for some reason it says "Ambiguous use of 'fetchRequest()'"
once I implement the method :| btw @FetchRequest as far as I know works with SwiftUI
Thank you for this, I have been struggling with @FetchRequest NSSortDescriptors - this has sorted it out and a predicate as well - well played 10/10
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.