Filtering Core Data

Learn how to filter Core Data fetch requests using NSPredicate to retrieve specific data based on attributes like an ID.

Swift Tutorial #18 — Filtering Core Data

Filtering Core Data

Note:

This tutorial covers how to use NSPredicate to filter your Core Data fetch requests and retrieve only the data you need.

Overview

Entities in Core Data can have various attributes, and often you don't want to fetch all the data at once. One of the most effective ways to filter this data is by using an NSPredicate within your fetch request. This allows you to specify conditions that objects must meet to be returned.

In this example, we'll demonstrate how to fetch a specific item from Core Data based on its unique ID, which might have been selected from a UITableView.

Reference:

Using NSPredicate to Filter a Fetch Request

An NSPredicate is an object that specifies how data should be fetched or filtered. You can think of it as the WHERE clause in a SQL query.

Let's say a user taps an item in a UITableView, and you want to fetch only that specific item's details from Core Data on the next screen. You would pass the unique id of the selected item to the details view controller. Then, you can use that id to create a predicate and filter your fetch request.

The Code

Here’s how you would structure your getData function in the DetailsViewController:

  1. Get the id: First, ensure you have the id of the object you want to fetch. This would typically be passed from the previous view controller.
  2. Create a Fetch Request: As before, create an NSFetchRequest for your entity.
  3. Create and Assign the Predicate: Create an NSPredicate with a format string that defines your filter. The format %@ is a placeholder for an argument.
  4. Execute the Fetch: Fetch the data. The result will be an array containing only the objects that match the predicate.
// In your DetailsViewController

var selectedID: UUID? // This would be passed from the previous ViewController

func getData() {
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let context = appDelegate.persistentContainer.viewContext
    
    // 1. Create the fetch request
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Shopping")
    
    // 2. Create the predicate to filter by ID
    // Note: Use 'idString' if your ID is a String, or 'id' if it's a UUID
    if let id = selectedID {
        let idString = id.uuidString
        fetchRequest.predicate = NSPredicate(format: "id_string_attribute == %@", idString)
    }
    
    fetchRequest.returnsObjectsAsFaults = false
    
    // 3. Execute the fetch request
    do {
        let results = try context.fetch(fetchRequest)
        if results.count > 0 {
            // We expect only one result since IDs are unique
            if let result = results[0] as? NSManagedObject {
                // Now you have the specific object and can access its properties
                if let name = result.value(forKey: "name") as? String {
                    // Update your UI with the name
                    // nameLabel.text = name
                }
                if let size = result.value(forKey: "size") as? String {
                    // Update your UI with the size
                    // sizeLabel.text = size
                }
            }
        }
    } catch {
        print("Error fetching filtered data: \(error)")
    }
}

By using a predicate, we have successfully retrieved only the specific object we were interested in, making our data access more efficient and targeted.


Note:

NSPredicate is incredibly powerful and supports a wide range of operators, including BEGINSWITH, CONTAINS, LIKE, as well as compound predicates using AND and OR.