How can I make a dynamic SwiftData predicate?
Generated on 7/30/2024
1 search

This post is brought to you by Tailscan,
the best devtool for Tailwind CSS.
To make a dynamic SwiftData predicate, you can use the new expression macro introduced in iOS 18. This allows you to build complex predicates easily by using expressions that can reference values and perform complex evaluations. Here’s a step-by-step guide based on the context provided:
-
Basic Predicate: Start by building a basic predicate using user-provided search text. For example, if you have a search bar in your app, you can filter trips by checking if the trip's name contains the search text.
-
Compound Predicate: If the search text might apply to more than just a trip's name, you can build a compound predicate to also check other properties, such as the destination property on a trip.
-
Using Expressions: To create more complex predicates, you can use the new expression macro. Expressions allow for reference values that do not produce true or false but instead allow for arbitrary types. These can be used to represent complex evaluations using a model's properties and can be composed within predicates.
-
Example: In the Trips app, you might want to create a query that fetches any ongoing trip where there are still some sites left to see. This can be done by building a predicate that specifies the trip should be ongoing (current date falls within the start and end dates) and that at least one of the bucket list items on the trip has the
isinplan
property set to false. You can construct an expression to count the number of bucket list items that haven't been planned and use this expression in your predicate.
Here’s a code snippet to illustrate this:
import SwiftData
// Example of a basic predicate
let searchText = "Beach"
let basicPredicate = NSPredicate(format: "name CONTAINS[cd] %@", searchText)
// Example of a compound predicate
let compoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [
NSPredicate(format: "name CONTAINS[cd] %@", searchText),
NSPredicate(format: "destination CONTAINS[cd] %@", searchText)
])
// Example of using an expression in a predicate
let ongoingPredicate = NSPredicate(format: "startDate <= %@ AND endDate >= %@", Date() as NSDate, Date() as NSDate)
let bucketListExpression = NSExpression(forFunction: "count:", arguments: [NSExpression(forKeyPath: "bucketListItems.isinplan == false")])
let bucketListPredicate = NSPredicate(format: "%@ > 0", bucketListExpression)
let finalPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ongoingPredicate, bucketListPredicate])
For more details, you can refer to the session What’s new in SwiftData at the 10:18 mark.

What’s new in SwiftData
SwiftData makes it easy to add persistence to your app with its expressive, declarative API. Learn about refinements to SwiftData, including compound uniqueness constraints, faster queries with #Index, queries in Xcode previews, and rich predicate expressions. Join us to explore how you can use all of these features to express richer models and improve performance in your app. To discover how to build a custom data store or use the history API in SwiftData, watch “Create a custom data store with SwiftData” and “Track model changes with SwiftData history”.

Platforms State of the Union
Discover the newest advancements on Apple platforms.

Track model changes with SwiftData history
Reveal the history of your model’s changes with SwiftData! Use the history API to understand when data store changes occurred, and learn how to use this information to build features like remote server sync and out-of-process change handing in your app. We’ll also cover how you can build support for the history API into a custom data store.

Meet FinanceKit
Learn how FinanceKit lets your financial management apps seamlessly and securely share on-device data from Apple Cash, Apple Card, and more, with user consent and control. Find out how to request one-time and ongoing access to accounts, transactions, and balances — and how to build great experiences for iOS and iPadOS.