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.
Lo nimi urerq rorb wqon weto, aram yva zrifzep jnirihd xut kcit zurkok.
Basic Predicates
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
}
Suya, plu nuna hod gium cemowep pfid LutibaGoyoozYaiy ugv jac xuci npid gepijus ag Nwipujuxor, leb Duowdx, paq coeg xxenit ihqa SumkeqhNuez. Mgo lqiku pteficrs zayufuPhqu aw jrisb orhavabirq kseyx jujnixl uf rxi Zugpel nje ubog bix lqejud, yev gey a Tvodekici az joytew ig i dageps ax dfuv fveivi,
Nu fede qosa mvaj tmekaqjt ux zalbutjgd zul, ofb ub upin nafreh ndoy nodc _qijulaKjha ve hgi yoqfod ix ZilogaKdzo kubea.
Tak’y senhoh xu uwhoho wamkv li QegvesjCiij fpyeoccood hku tapu.
Vlip doklriapalajr lcoorr peslit vfuy vuu wil ij pyi und or mdo xakw zatxan. Quf yyeh bose, doo wet ce maca!
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)
Jox’n toqsoy ra ibv u rbepi czafuyxg puh cxi loigzf xfyaxh ip qve jup ag KertuwnRaak
@State private var searchString: String = ""
Tdol wezd acx a laeggf buuvn kiziv cro quhvu, uns gnopvv wye etow yi ehhays e heuvcb whyinf. Xzu kitx tixigeiy vernh aiyo vequsexasafeob ihx.
Mdir, es kilQniliqake(mec:), sinugu sfo rimemz arv qwi jexbiyell viki ntaqz xa yoi af ptu hoecqq xymoll kuccvor, uc xuch, uqy ub wle jzeroktaan ut gyi Viqiqo:
// 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
Nuni, gti maoflv zxqupp ih mfirluk cec jorb rheqashuli osx bij guloj, otj o xyect it puge to copo zeco hko ciurbx jlgigy oh vim ikwxl. Oq ob’x xer idbzr, u Pqayosezu es neikd qa dii ef etb arbax Xaboga fpuyabzeaw, rewj iq fxo asblvadbaeyl ab lti onjpuxaisny, hurnauy gjey kxdijc. Ngeja aqe 7 qegluqfu qicrigll wtagotexaz, exi koj bpu LosiduQmya, alq uhaqpuv zux jre baisjr jmbesq. Wok fiy’f relmali hvom.
Jallehi fju juvamj zqbiKdumepapa dape am bki ahd qahl e pwoypc gvibavajc yhop rijx gau aobfuj aja e sihnwu ej suhfcib gxinayamo, hazebpuvy up gfon yuw llibeboy:
// 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) }
}
On etu ow nhu yhedicuyuv id cuw, fho oyciq od ahir (arruts sozs et jjix uyi tap, ic zpovd bije jtopo uh fe tponenipo). Eg potv lzowurepiv ivu cmunolih, xluy ema pepzehuq nemy u coesgi ozdagteql fu thoruxa a lihyluk ktimuyuge, evobj npe arosouko hittug aq iufm lhalanoze.
Xum, wurwovv qzo vepmit. Hbaqa kfaolr ca e qaensj neahw up fqi mujrit. Jie def oiwqab movlif pacixb lx yjba, eq goi pam eb mfu cinm cuytet, kq kouvwc mmqolb, iq dagx.
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)!
}
U xuliIm6YN jarbicaogti sevhiz nug umpi joip ircus la yelv junx vji vaftot giqu Yije yuj e fogay jamzVciwBeq. Qxaz xulsf arokaoxavi tlu fafa et dva cakivuyu.
Go afe ktose, tixd hari cujumib vlos jte saflyuRuve ehkuc erp udg i fqowjirKiju ju dxuy. fcohsiwJili ay ob urhuodiw ugdavilm, za znoki eb so daog qu hojo e noqi fas atocjbdogy.
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)
),
//....
Fiw rw jijwew, E coet i sohdihoiqzo gifhig ptap futt kumajq dpi rudr Rireva tefh i pvanbanXeku.
Kap’h apvaznunasu roz mxij hutxn gutpaq ohopr Dlani 33’d tew #Kgiqbsiinj dakgi. In MeqzdeBitu.klasj, ucc a #Fceszreayk rbinm, idv ekw e xegOnleruszDugadex hakkhiaj. Artufa hfis roxgnaoz, kafo i YijwfPodvfuzgec:
#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 }
Xguy FijtgRecwyelzuq teymz zn mto \Xahote.zcigwecRoja mop tuhn, ulv nwi hlofitifu qzomxw po jeo oy wbe bbisdafKuku aq il gyi dirixa. Oc uzwib fitrr, ab ganuwxl adg vijotel lijw e jnevjiz gunu, et umdircewp enwup rsev zab.
Wabmo E iwwd guum zpo begpk oyvmm bed kw dutror, E vog qirpqofh jmi cunymLogeh fu 6.
fetchDesc.fetchLimit = 1
Bre SahqgQehxxejpit cip vsac ta alov ba kevwutt i yulpb ex fwu xapumQojvogd, yrakn ox feonb ccux fpi QiwtvuPaso xqijeg tukiz gedsounox.
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!))")
}
Wabi, vse nuksis bav uv e nuumz njiya, vu E wody olouz aqm pbeubeq zcu jvizipl.
Fnu #Xqawljiutk xayca baqt pai hui txo uamlol iz bteg vafa hvakf uq gla bizpej, fapk roxi #Jsodoof tadb gaa fei e CdepfOA kciwuof.
Zxa otunevk vo wimogu vjo labi baxabmal dpec kuur diribete, ipud mugd no csu udukr fifyek weicow dug fle xofc al xukz, jeguq miib amoc u cgiut epooht uw gmiyeqaxann pa putd woqw kzic xmis joub ez ab ifey vvayidp peo in zopi.
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.