A few years into using Slate on real projects, two things were
clearly missing. First, the API was completion-based, and the rest of my code
had moved to async/await. Second, I was constantly reinventing the
“observe these query results and refresh the UI” pattern, and it really
should have lived in the framework.
Slate 2 was a refactor to fix both. The primary read API became:
let books = try await slate.query { context in
try context[Book.self]
.where(\.pageCount, .greaterThan(100))
.sort(\.title)
.fetch()
}
Mutations got the same async treatment, and queries gained a typed predicate
builder (.where(\.field, .equals(value))) so you don’t have to drop into
NSPredicate format strings unless you want to.
The bigger addition was first-class streaming via Combine publishers:
let publisher = slate.stream { request in
request.sort(\.title)
}
Subscribers get snapshots that update whenever the underlying data changes. That’s the bread and butter of any Core Data UI.
The one thing Slate 2 still inherited from v1 was the requirement to author
your data model in an .xcdatamodeld file and run the code generator against
its XML. Fixing that meant waiting on Swift macros, which is where
Slate 3 eventually went.