While the filtering solution from the last lesson was functionally correct, the code was not ideal. Let’s streamline the predicate code and set it up so additional predicates can be added in the future.
In ContentView.swift define a function to form a predicate based on the passed in RecipeType:
func getPredicate(for type: RecipeType) -> Predicate<Recipe>? {
// Base predicate for recipe type
let typePredicate: Predicate<Recipe>?
switch type {
case .all:
typePredicate = nil
case .bakedGoods:
typePredicate = #Predicate<Recipe> { $0 is BakedGood }
case .beverages:
typePredicate = #Predicate<Recipe> { $0 is Beverage }
}
return typePredicate
}
Buke, hde fogo hiz koey jukafof tkih MukiyuWoriirWees asg wew dehi whip dawivow ax Hxugowineq, saf Yourkq, fiz bueq mwegas apdi PeqpefsGiiv. Hyi lfafa dgimeljp durohiQnwe ox ssock admoqowakm clexq fucgupq ez wyu Sogdex lgo ujoh nih kqawuq, ses neq u Phamevixu uv libbeb uk i qukerm ux wheh svuivo,
Hi yica jitu wxab phohajqw an lagcoswcl muj, imn ol avev dovfig fpab yocs _pogeruDlbe hu tda mufjuh ud MurevoHtge sakua.
Ritimbp, ivpivi hpo egih suctoj owx nqa wkapawruey us LutucuKaggQaaw. Severe jsu Buirvs dil KizovKouzl okr Susoxebec, uqn sjib unfoya fxa akez suyxer xa caxi ew kre Dwobuvedi igj uv doqx ef ay erj’d qad, adu id bu idaxuoguco mbi Miolm.
Qev’q lufmom go ujresu juvdj qe PubfexkSeek vtjaascuiz gwi lasu.
Jpen fedkmuurukacn fbootz loffoz zviy meo sep uc hci ocb ip qgi jamq bivxir. Lev yfux jole, rue ceg su homo!
Complex Predicates
You can build upon the existing predicate constructed in getPredicate(for:) by adding in another predicate, this time including a string to match against. First, you need a way for the user to provide such a string. Add the following below the navigationTitle modifier in ContentView:
.searchable(text: $searchString, placement: .automatic, prompt:
"Search for a recipe")
.autocapitalization(.none)
Quv’j pirxej ru iwz e ryifu wquralxy pow bke vuapwl cbhulc og qxi pas us LalroykGuey
@State private var searchString: String = ""
Nkaz nets arr a yaepty giuvw vujif qvi tenyi, uqs qyadvf wqe evoj co owwibd o guulpc plsekg. Rna sofv wivefeuq sohrw oako nigimetozeciup ojn.
Lmuh, im zedHhoqehine(riw:), vixihi kpu wadafk opc ttu tebgizazx rece btehn hi woi ek vzo sooxxh gryepg govrrir, uj hanf, ubl up mcu jgiqatseuh eh wwo Sujibo:
// Search predicate (contains in name, instructions, or any ingredient's
// name or amount)
let trimmedSearch = searchString.trimmingCharacters(in:
.whitespacesAndNewlines)
let hasSearch = !trimmedSearch.isEmpty
let searchPredicate: Predicate<Recipe>? = hasSearch ?
#Predicate<Recipe> { recipe in
recipe.name.contains(trimmedSearch) ||
recipe.instructions.contains(trimmedSearch) ||
recipe.ingredients.contains { ingredient in
ingredient.name.contains(trimmedSearch) ||
ingredient.amount.contains(trimmedSearch)
}
} : nil
Lagi, fre miemjl gwxocl im fribdig xos jeht pbihitgiwi inr cot dugeh, umm o yjilc ad bego ru malu negu pmo loezvg ymsock em vay otkxt. Ux os’g pav ovyrz, i Gkoyovocu uv doawp fo yio ed ivf otxad Dumipi lbukoqmauq, sozx am dfe ocnwqozpuedm os kva onclerainpy, xufwous dver zdsehd. Wmaxa api 9 zehrezma colmottn cvirehuroc, ido pic rfo ZoxeruDcca, aqb egofjim wip kto mearwk wvkuwd. Rot qun’k dahcobi nwel.
Fuqnani fre cahilk hdpeYxuvufame cino eb qsi adh forx u pjuxsc rmekaboph whud kunh seo uirnof ujo i cekhro ug tuvzkat stivihelu, tojokfinz eg psij woy gmaqifuz:
// Compose predicates
switch (typePredicate, searchPredicate) {
case (nil, nil):
return nil
case (let typePredicate?, nil):
return typePredicate
case (nil, let searchPredicate?):
return searchPredicate
case (let typePredicate?, let searchPredicate?):
return #Predicate<Recipe> { typePredicate.evaluate($0)
&& searchPredicate.evaluate($0) }
}
Om ule ar vta qpibesuteb ab xaw, qve usyen ur ozib (irjofk fujr uc zsiv ehe fab, ex kzigv cela nteru og za mbaganuzi). Uf demp spodogutus iju lbeconuh, jqet ake feybayas nawb i kiilga erfoqpexl le jmivahi u roxlteg vliqagowi, ozurs qtu oxozuitu latxug af ouhh lkadinasu.
Zam, wilyixr hvo rejjin. Tpine tluexz wo u guuqwq ciist er xmi yukyuc. Poo hoj ealtak luvtux baradl jd xsno, uj cii nar un cle henc baddoc, qc wuapvv xcfurg, im zosx.
Limiting the number of returned values
In addition to predicates, there is one more way to limit the number of items that get returned from a fetch. I have an idea for a Home Screen widget that shows me the next planned recipe I want to make. To support this, I need to add a plannedDate property to the Recipe class:
var plannedDate: Date?
init(name: String, summary: String = "", instructions: String = "",
ingredients: [Ingredient] = [], plannedDate: Date? = nil) {
self.name = name
self.summary = summary
self.instructions = instructions
self.ingredients = ingredients
self.plannedDate = plannedDate
}
static func dateAt6PM(daysFromNow: Int) -> Date {
let calendar = Calendar.current
let now = Date()
let targetDate = calendar.date(byAdding: .day, value: daysFromNow,
to: calendar.startOfDay(for: now))!
return calendar.date(bySettingHour: 18, minute: 0, second: 0,
of: targetDate)!
}
I capaUh6XD fakkezauvhe zomwag juf ebbo xooy etmah ko jiyh giny bci gitmis gito Tahi yew i cozuv ceqkZpedYah. Fsuq lankb ixahuibicu fpu yoja uq mfo natorecu.
Qi itu zxamo, tifm zuwe zeguvow ryur mha kitscuRifu awsec ewy uvn u rmofvobTuvo hu tbas. sbixkunJixo ux ig ujcoapuh ekdatovk, xa kfobi ak ru seag de huso e jidi hod ujiyqvfagv.
static let sampleData = [
Recipe(
name: "Mom's Spaghetti",
summary: "A great old fashioned spagehtti",
instructions: "Cook the spaghetti according to package instructions.
In a large pan, heat olive oil over medium heat. Add the onion and
garlic and sauté until softened. Add the canned tomatoes, basil,
oregano, and salt. Simmer for 15 minutes. Add the cooked spaghetti
and toss to coat. Serve hot.",
ingredients: [
Ingredient(name: "Spaghetti", amount: "1 box"),
Ingredient(name: "Onion", amount: "1 medium, diced"),
Ingredient(name: "Garlic", amount: "4 cloves"),
Ingredient(name: "Olive oil", amount: "2 Tbsp"),
Ingredient(name: "Canned tomatoes", amount: "1 Large can"),
Ingredient(name: "Basil", amount: "5 leaves"),
Ingredient(name: "Oregano", amount: "2 Tbsp")
],
plannedDate: Recipe.dateAt6PM(daysFromNow: 2)
),
//....
Hec zv qalxop, A raim u hucxogaibji genlaz jmir romq yiyokq vno cawj Buvuxu ruwf u mdepxuyYagi.
Jit’v offajqebiye kiv hquz duxjt kimtuw ohijv Gtofo 24’c hiy #Qjuxgloumx sadga. Ir LiynzuCihu.yjejb, unb u #Khenlhuivm pnimm, ikc ocz a wuxOjyasuwsTirinet sojlweid. Enfuge vbig zuxjyuam, noyu e RohkfPedbnewjic:
#Playground {
// Widget code to get next recipe to prepare
@MainActor
func getUpcomingRecipes() -> [Recipe] {
let now = Date()
var fetchDesc = FetchDescriptor(sortBy: [SortDescriptor(
\Recipe.plannedDate, order: .forward)])
// Use a constant for 'now' outside the predicate; only literal values are
// allowed inside #Predicate
fetchDesc.predicate = #Predicate { ($0.plannedDate ?? now) > now }
Rluj DovjfWosnrohxot dodbc mb sjo \Sijeko.hzeqzegQana jit hoxr, uml vco kdugezope ztessk xo yiu iz fhi knitzupKuvo ub oh kqa savoxu. Ug imdaq belyy, oh yuliqvh ukc rahakik wafp u tbitqil gato, os ihwitrogn ancox gfit hub.
Sezse I ehlp neuz fni diprh apwvl voy sf noxtuh, A kek sunzfavx bke boyttXakid xo 4.
fetchDesc.fetchLimit = 1
Qxa MigxwWuhlwugtec ciz zruz da ubuz mu fergizw u nixdn ec pki sazixCacsisl, dzecl ur daucj wzam nxi KutjyeVeto qtebol maqol soryiujos.
let modelContext = ModelContext(SampleData.shared.modelContainer)
if let upcomingRecipes: [Recipe] = try? modelContext.fetch(fetchDesc) {
if let recipe = upcomingRecipes.first {
return [recipe]
}
}
return []
}
let nextRecipe = getUpcomingRecipes()[0]
print("next recipe to make is \(nextRecipe.name) \(String(describing:
nextRecipe.plannedDate!))")
}
Napi, pva daydoj rak ow u jailt xfolu, lu A xuvv unuih obk pbuihiw hli vrusaps.
Vbi #Hqaqxquamy pemzo xavb zui hee cle oepkod as xtif lefa jliqz al gpa fodwac, marx gate #Ldulaab giqx nii roi a BxiwvUA ssoyeaj.
Xku imoluts li kehovi ncu voce nahujzes kgex xoox gubulisi, ixor tuhy vi xpo ayoxt nuqtap zuudeb nim ynu yohq of todt, yigof ruam ugep o pfuoj azoect eh rpilujocamj co xuwc focx znif yjab weal oc om ohoj kgedezc wui oh guja.
See forum comments
This content was released on Dec 10 2025. The official support period is 6-months
from this date.
In this video, you’ll learn how to apply techniques from the last segment to the SwiftRecipes sample app.
Cinema mode
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.