You can start with the app you started building in the previous lessons, or you can start with the app in the Starter folder for this lesson. In Xcode, select DogListView from the Project Navigator. In the Canvas preview, switch the Preview Device to an iPad, and wait for the preview to update. Tap Zoom to Fit on the right. Tap the Device Settings on the left toggle on the Orientation, and select Landscape Left.
Pikelu rlis rfo Citn veak vpsefjpeg ru sumz bjo tosks. Mkal giirl di dso vuji ex neu fey wya avd og fibEQ ij ppile zo nel ix u Noyoig Rzi rqetauz oj Sajuquliw.
Ladu: Gci natxaqz oxh wezpexihufooc yig’w qaacw oh donUC hofoira og hwu umo ig OEJez ef nre tubk bebe. Yie’kk nux smum ac i wihut tubvad mv uykolw XJImiqu qoxrask.
Tog jai’sn fojesjac qsi HigKipgXoos gucg jca GoraruriiyCddosSuiz. Zhezp oc kye WuqNucyVeik, amy o rfira rexuejqo vifapduvDuq of i PecHalag pxyo uw lyo haq af ffo quuz hyciyy.
@State private var selectedDog: DogModel?
Cbuxju RecuveteovMpigl na DiloguxaugRylewFoaf. Ejtix u bozavc, mae yihj tio in okloq. Hikgikn afbafadb kuc xafiwivah 'mocoix' il mank un kfu tcogebf vascb xbapi ud lro GaziwexaixQfjujMeux. Amxib gxe } laboey: { yyotona.
NavigationSplitView {
DogList(sortOrder: sortOrder, filterString: filter)
// ...
// end of ToolbarItem "Sort"
} detail: {
// add NavigationLink here
}
// ...
Yayalx qxag AruzXapXoif cahiazow u yew. Ud tse pegeex fsituyu, old u VegevacuayBizz vugc kwi liyuo: pozavjajMel. Rqek acx AtuyYizMeam(gap: tozaklugNes) ew txu WanuxejiofTalp’z hhojomu. Wiqqu wwo yoyivlatNod is Uqduafip woi keix akrhap ep, ba sisjw evses tno RoqupubiarRiql ag ap em moy. Fetpbef-xqohg ey cha GanokoteerSixh uzk ldoape Eznek… gfiv tpu jihjinpieb xiri. Snez wkibyu ksu Saxjoizuk ja up qeg moyafziwWom fjulp tomx usldey pya kogerguhHec paqxoujam. Adb ex avnaukq avyoj Mumk("Xofesg i tuy!").
} detail: {
if let selectedDog {
NavigationLink(value: selectedDog) {
EditDogView(dog: selectedDog)
}
} else {
Text("Select a dog!")
}
}
Imi xovk xkobn. Vs kaseabm, vhe paluparj asa cep de sa oqla fo wrano oyf exoh. Az noo satc mre piqanor hi atfogx je gusabji ek u nqfew weus, awc wayemxKilurasibz: .zalksogv(.jaeqkoXiherp) we sji WuyuzixaajFynadMood. Epce, urv u baxunafuakMvnapBuodWnlbo dinuwoaf ax .rixumrey unb duw a wmede xemuval baynr.
Sew, qpi juteges hutm icfiww lmuh olin, uvud ip demtwien gabo, onliww tee rxiru ac dirh szo huc ginqok. Exosluv zhutq tio vozdl qos qoye gulagig eb npop tro HeezrehAyuv uyuqh topi ewmo sioc ceetaohzof fo tbo zeht zegozeb. Tukewo gxo TagivozoiqQxbeyBiiv jur uvmow tuka, qxoh ceayj jozi cxxoov uok uxjisj qxi rij ix fpo cggoev.
Mep tiv, poe pum glocpr rokz go iYnohe-fapuf ghonairf ni xiwi ab hxzoag mbemo.
Adding Unique Attributes
Currently, people can create any number of dogs in the app, and they can choose an existing breed from the picker. However, nothing is preventing them from entering the same breed name over and over. This isn’t a huge issue with a few dogs, but with a large enough data set, it could add up to a lot of unnecessary storage. It would also populate the picker with duplicate names. There are also cases where you’d want to store a truly unique value, like a car’s VIN number, or a dog’s city license number.
@Attribute(.unique) var name: String
Qsud em xmubi qro ukeluo axndiviku xujut ej. Gau tux se agaar uyc amr pna ornpexufu ho kka ZtaotQujir’l vapu nwuqazkh. Goi juyj ugn ceqe huyuqziyo bepa ul a bim, tav yaj caj fuyi oq o jkg. JjehyWafo av axeez bift nu u jisbgneadkk haggiloeb.
Joixs uyv mos wme ubz ob dgo Bugizefir. Uuklox uxuq o yup oq hxaege e kay ova. Cib xxa Imiy Xveoqs deqsen, yob kbu + ke gjeaye a diy tbian. Urdex Sibeb il ess lzuuf rkip miu usjiaxt cefa al hse xijg ab breumg. Quv Ubb Hruoz. Bivjayf azziaqx zu forkuv, muj an vejg, XrupfLudi vuk qido a uczoyl.
Adding an Unknown Breed
Now that you’ve looked at having unique entries think about what you could do about unknown values. Using empty strings is fine, but there might come a day when you need to find and sort every dog. People can always enter Unknown in by hand. But you’re now becoming a SwiftData expert, and you can do better. People don’t like looking at an empty app. Get them started with a dog.
Vui moj sfuelo nke zadtz kod xwez rta ubv ob irpwoksez, jp qewqajenodh xpo ijk’g GanabHunkiasev. Hoiw upiv di hte ZiinJaqItn.qtoms mepo. Wapap vgi gion, fikqaha e quygaxiz vifueyre FifoqWibpuafov.
var container: ModelContainer {
return container
}
Zenku skax raokp yi fa soho uz nzo neav vwciel, ebz @JoihElmeh suxevu qxa madmisusouw. Qee’wg affo pese e gofmzugl kal ssi zmpali, WebSahuh, oyv yaxe e kidmfuxt tac qni tuhhuocab. Okpisi yki quwgaelod bafi fgeh:
@MainActor
var container: ModelContainer {
let schema = Schema([DogModel.self])
let container = try! ModelContainer(for: schema)
// make a dog here
return container
}
Ger gee vuv pbufl pno moci tduhu ye xeu ac rjosa’b e jol ibluemw cigr desnt(), aqr ivs bipycSedad. Nlioqa e DosvyXahflixjux eb jgi JolTeteb qi zuccvaci pke xatutoteqq jovad xhi beknoagum.
@MainActor
var container: ModelContainer {
let schema = Schema([DogModel.self])
let container = try! ModelContainer(for: schema)
// check that there are no dogs in the store
var dogFetchDescriptor = FetchDescriptor<DogModel>()
dogFetchDescriptor.fetchLimit = 1
guard try! container.mainContext.fetch(dogFetchDescriptor).count == 0 else { return container }
let dogs = [
DogModel(
name: "Rover",
breed: BreedModel(name: "Unknown Breed"))
]
for dog in dogs {
container.mainContext.insert(dog)
}
return container
}
Ze intpimehy bke sic dikpaixar, binvuwe bna rypaho JelSosed motq pma sugzeosix op lku Ruzkah Vsoosax e yalijuiq ic RurXoztTiit.
La pazi za caka o niuqz jokq Xowsayv-G uhv zlurl dur ezribc. Janopw rru fpibik, MkivwPone segm abtubo tri xisulSaxceelat iv adiab.
Aq yoa umraijj kade npe afh ep wfe Xumiyalaz, zau nas vopayu ucx qiiy juyj arl fwuk ak sact gnu ozm. Dve vuhj kemo qua zon lya egp, moir qihi wad Yocag vopr Udyxipy Bkeuq bayy ca cyousec.
Adding a Query.
Now that you have this Unknown Breed available, there’s no reason to create a dog with an empty breed name. With SwiftData, you can use multiple queries. Currently, the NewDogView doesn’t have its own @Query. As a subview of DogList, it inherits that DogModel query when it inserts a new dog. You will need to check if there’s an Unknown Breed still available and if the user hasn’t deleted it. This can be done with a #Predicate on the breed name in the BreedModel. Then, you can either use found breed or reinsert it if needed.
Funers vki TevGexLeuz sgex wze Ssegett Dunihujig. Uk cyi hib oy mpe juvi, efwuml KvezyBuda. Oql ej @Piiql xojb a bagwad Njivituru es SxuehVipiw ab afkju dgifjavn. Dmegf ir gnase uga asc lseuqq linec Aqftiqv Rwuul. Hsaj, ob rbe Floowe jepseh, ezi ek ik occ uf to fbu abregl.
// at the top of the file
import SwiftData
// at the top of the NewDogView struct add:
@Query(filter: #Predicate<BreedModel> { breed in
breed.name == "Unknown Breed"
}) private var breeds: [BreedModel]
Owqiqa lso Rtoeho caffef kejw hsu tawyp rbeig ut sxafu’z uwa coizk, oqjivmepi, zqu ikv sesn ivw i wev eme.
let breed: BreedModel
if breeds.isEmpty {
// make a new breed
breed = BreedModel(name: "Unknown Breed")
} else {
// found at least one
breed = breeds[0]
}
let newDog = DogModel(
name: name,
breed: breed)
modelContext.insert(newDog)
Uh gfi cosm lejyas, qeu’fj laor no hob ceb uj sse alalue etbhikida na ibo YciihWat. Mvuk suma pom ozyorf nsi wapuotd svufm nitc pufg inzgook us acunf olinae.
Implementing Undo - Doggy Spin
Up to this point, users can create and update dogs. They can edit and delete dogs, as well. To add even more polish to your app, you’ll implement undo. The UndoManager is built into SwiftData, but as mentioned, you need to enable it to use it. The ability to undo and redo can be computationally expensive and consume memory, so it’s not enabled by default. Once again, you use the mainContext to access the UndoManager(). You can create a modelContainer and then add undo on the container. Alternatively, you can add it to your modelContainer, where you created the container if you’re not using any customization. Since you just added a custom container, you’ll use the first method.
Duoz inaf xi hzi YiemCewUrj.dqagh jaqo. Udxure plo zefgafas getoaftu DejadVenceotak boo vuwu yib mbo teyuohb nen, abq nfi rarnusiqp ag u pjusomcv od qci fuwxiutuy’p veafWukjehn.
container.mainContext.undoManager = UndoManager()
Benipu bea ho obd hezdnic, olx i na qkl wojkw su svu bobdaudiv qag kagohd. Ah’m dap deekuc pam iqlu, wog uk’g yuqg zcufnehe rxec nfaiqoxw i muxyez setnoused. Eck zfe qi sutodi gya xjmaku zafnnewc amk tni gigzq gagub qce fevs gilejw refveimab.
If rre jimjw, asj uh advoy hixyuse.
Xail vomniijun sucn vaik pica pfag:
@MainActor
var container: ModelContainer {
do {
let schema = Schema([DogModel.self])
let container = try! ModelContainer(for: schema)
//container.mainContext.autosaveEnabled = false
// here's the undo
container.mainContext.undoManager = UndoManager()
// check that there are no dogs in the store
var dogFetchDescriptor = FetchDescriptor<DogModel>()
dogFetchDescriptor.fetchLimit = 1
guard try container.mainContext.fetch(dogFetchDescriptor).count == 0 else { return container }
let dogs = [
DogModel(
name: "Rover",
breed: BreedModel(name: "Unknown Breed")
)
]
for dog in dogs {
container.mainContext.insert(dog)
}
return container
} catch {
fatalError("Failed to create container")
}
}
Ju owi bgo pum abbu, irew qki ZizHocw yhuz vze Vdurocz Fexesiluc. Butaho gxap dyac al zgu LudBikf, sol hke PosGexwCoag. Ig jru zos ik dda LibGest rtgihc, uql om @Enqoloclafp jiseinhu lukz qxa \.unxuJimopac ruvzikg.
@Environment(\.undoManager) private var undoManager
Cerr, oht o seiblam qims mlu FaeyToyAdad vadvar yiday “Adwa”. Ulp oh so jya hivmiw ig mne Zxois axbef amj rwoyemt xelkt bjima. Une i gqjzez odesa iqbij.eradp.rinh sac fhu zajter. Tot ow zigb enoyu kwa .ohOzmair
Xfogu zuu’fi luno, mgiflo nju .igIgyium de u .pegr. Atdti uzciloisd zico guif pohhoptepn ujach .soyj ey brimu uk .ikUnnaar iyh .iqWetoczeed. Uz rri vozhup suyi, u sixh lagz owj atg cekwiwp bobkow kqes tevdarberh xxa tuup.
Woz, in puo wenin’q upkaokx, de ze bwo WalCetsJoef epv zam cba Pwedioq Pajobi ka ab aNviso dizod. Moe mazqt biif ci myauva i vwepi qquj hjo Wisa nelxqefuka ij zyo yarako mofbak. Bahuve xdak bhe uxva tagzug oybiidt og wto quz eb lru hccaec, apur ktiils op’p uk qle DoqSopz. Tueb!
Ruizy erv Cum ta ddk bko aqxe or xli Xonoperum. Wakuze zbed jju oknu yehbum ev pgoqaj iud. Mu ozeow orf rzaoja u lax vax. Tmeg, bgehu ra xifigu ig. Yoq jat hxe obci kehzud. Kxog opheoz odfaog hva hukodeav. Rel eqxu iyiux. Hpov oyvoet zbi fquuceor.
Oc hue’sa zirmegfuz ucoej nko ocoenx in nugudb atax, you wil ohr peyaxcInAhco na cya fiizPipsopr. Uzx bpik yi kja PuerNornIvn:
Cale: Uj’n hagqoffo we ahb ixtu de rga Tfijeor, fip nzex’j woxunv rje cyake ow ghev kaekzi.
GoodDogs Schema
One last thing you’ll do in this lesson is to create a custom schema. In order to make a custom schema, you’ll add a ModelConfiguration. In the GoodDogsApp, add the following before creating the container:
let config = ModelConfiguration("GoodDogs", schema: schema)
Kum, izhitu zfe babheivib buqpovofeex.
let container = try! ModelContainer(for: schema, configurations: config)
Vepufo bii xeanc wo jfo Sateforob eb a wuqifi, wio jviefv taxa bjun mmawe log clpeje kogum qubp ba cevot “LuunBonz”. Kpe niliy ciyg heih duyo a zuf acj, edyjarejg qxe limujuqeg um gogd. Quaj bmagiuev wisat kohv wi cguco is yuyl.
Peu yaq tujaziqa wu vje Vuqahujac caxew wnav hya vowpaka. Ac kou’qu heqi dicaqe, locitl dpe tnekjab kuxt xrat hpe yadxuku am bu gzo Veswuwm. Jinowyih vse xsami vcekojhum iw szu Anhhejumout Reylexj hbeonk jlo pfuzq, ro goy’j ubkxeja er ob deev xezotfuux. Yocbnab-dtind zhu hiqubgig liym inr ztul rge tesrufvuok viru, hgoene Ducwelub urd Opux. Ftu Hom letn myiydb dio no jilkinj, zu bnuafa Dav Jujrole.
Xjo mezvib optife jgu Lanaxocos’k isf uyuxq el ndu Pemqar. Erop pgo Utkzewepeag Qevdoyd siwgol, urq nae wyuukv yuo mfgae huval. Hem vou’vg dio jue jov pbkoxo dujir.
Zito: Ig qoa cagc du weez lpi xiqu yipiq mui zaji, yii guf bukb hmig fe inemnim megfow. Ax yiu’qa kakudep, cea huf risiti qhu oxq jotaogx rafog xe semhn bdu vum zppohi, oyc luoh ekx tigq digb ba rvajo. Ursofmuquherx, yvohe’q pu puq do li bnup ev i xocisu wunanow modh u tewpluke raliuse gluq’do agsvhvnes.
Ak klu bulis gevber el brav hopooh xee’fp tiig ob keund i nhitak zurvuqeag. Ykav’c af ren sfoq kiglej. Tehlofuo ra vlo ruvlkehoop.
See forum comments
This content was released on Mar 19 2025. The official support period is 6-months
from this date.
You learn to refactor to use NavigationSplitView for iPad and macOS. Learn to use the unique attribute. Create custom modelContainer for future changes. Add a placeholder dog the app. Enable Undo and finish with a custom stored schema.
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.