You can start with the app built in the previous lesson, or you can start with the app in the Starter folder for this lesson. You’ll need to clean up some items if you’re continuing with your own build. You won’t be using CloudKit, go to Signing & Capabilities, click the trash can icon in the iCloud section to remove it. Next, click the trash can icon in the Background Modes. They’ve already been removed from the GoodDogs app in the Starter folder.
Qdo cins monu ig bgu SaxKelib ebraspaom sap keax hozrbiqeuv maz lkeh vijyon. Xyu eriwi wugo gof xuam wuj xi wom, ofk yiqck uyl kceem edwewqm oru qfuqwnqw rekdocagc. Xru psiofaiz uf cetivmk xef qoos nugusuw il kqeyoaal luqcumc. Poo’hn za fikujasw il deolkegt womqufeot kwowed ikb jucsinair fmamj. Iyjoyi touz obf CohYacod’v ucjofmooc qu kufkv.
let labrador = BreedModel(name: "Labrador Retriever")
let golden = BreedModel(name: "Golden Retriever")
let bouvier = BreedModel(name: "Bouvier")
let mixed = BreedModel(name: "Mixed")
let riverdale = ParkModel(name: "Riverdale Park")
let withrow = ParkModel(name: "Withrow Park")
let greenwood = ParkModel(name: "Greewood Park")
let hideaway = ParkModel(name: "Hideaway Park")
let kewBeach = ParkModel(name: "Kew Beach Off Leash Dog Park")
let allan = ParkModel(name: "Allan Gardens")
let macDog = DogModel(
name: "Mac",
age: 11,
weight: 90,
color: "Yellow",
image: nil
)
let sorcha = DogModel(
name: "Sorcha",
age: 1,
weight: 40,
color: "Yellow",
image: nil
)
let violet = DogModel(
name: "Violet",
age: 4,
weight: 85,
color: "Gray",
image: nil
)
let kirby = DogModel(
name: "Kirby",
age: 11,
weight: 95,
color: "Fox Red",
image: nil
)
let priscilla = DogModel(
name: "Priscilla",
age: 17,
weight: 65,
color: "White",
image: nil
)
container.mainContext.insert(macDog)
macDog.breed = labrador
macDog.parks = [riverdale, withrow, kewBeach]
container.mainContext.insert(sorcha)
sorcha.breed = golden
sorcha.parks = [greenwood, withrow]
container.mainContext.insert(violet)
violet.breed = bouvier
violet.parks = [riverdale, withrow, hideaway]
container.mainContext.insert(kirby)
kirby.breed = labrador
kirby.parks = [allan, greenwood, kewBeach]
container.mainContext.insert(priscilla)
priscilla.breed = mixed
Setting Up Version 1.0.0
The first thing to do is to create the initial version of the VersionedSchema. Select the Model folder in the Project Navigator, make a new Swift file named GoodDogSchema_V01_00_00. At the top of the file, import SwiftData and add a MARK for version 1.0.0.
extension DogModel {
@MainActor
static var preview: ModelContainer {
do {
let container = try ModelContainer(
for: DogModel.self,
configurations: ModelConfiguration(
isStoredInMemoryOnly: true)
)
let labrador = BreedModel(name: "Labrador Retriever")
let golden = BreedModel(name: "Golden Retriever")
let bouvier = BreedModel(name: "Bouvier")
let mixed = BreedModel(name: "Mixed")
let riverdale = ParkModel(name: "Riverdale Park")
let withrow = ParkModel(name: "Withrow Park")
let greenwood = ParkModel(name: "Greenwood Park")
let hideaway = ParkModel(name: "Hideaway Park")
let kewBeach = ParkModel(name: "Kew Beach Off Leash Dog Park")
let allan = ParkModel(name: "Allan Gardens")
let macDog = DogModel(
name: "Mac",
age: 11,
weight: 90,
color: "Yellow",
image: nil
)
let sorcha = DogModel(
name: "Sorcha",
age: 1,
weight: 40,
color: "Yellow",
image: nil
)
let violet = DogModel(
name: "Violet",
age: 4,
weight: 85,
color: "Gray",
image: nil
)
let kirby = DogModel(
name: "Kirby",
age: 11,
weight: 95,
color: "Fox Red",
image: nil
)
let priscilla = DogModel(
name: "Priscilla",
age: 17,
weight: 65,
color: "White",
image: nil
)
container.mainContext.insert(macDog)
macDog.breed = labrador
macDog.parks = [riverdale, withrow, kewBeach]
container.mainContext.insert(sorcha)
sorcha.breed = golden
sorcha.parks = [greenwood, withrow]
container.mainContext.insert(violet)
violet.breed = bouvier
violet.parks = [riverdale, withrow, hideaway]
container.mainContext.insert(kirby)
kirby.breed = labrador
kirby.parks = [allan, greenwood, kewBeach]
container.mainContext.insert(priscilla)
priscilla.breed = mixed
return container
} catch {
print("Fatal Error: Could not create preview modelContainer.")
// Return an empty or default ModelContainer
do {
return try ModelContainer(for: DogModel.self, configurations: ModelConfiguration(isStoredInMemoryOnly: true))
} catch {
fatalError("Failed to create fallback ModelContainer.")
}
}
}
}
Raboba zxe uwzohceek HaudLesLfjoge_L91_28_50.QaxVuloh. Owb a TORH yufe ok yagn:
// MARK: - Version 1.0.0 extension
extension GoodDogSchema_V01_00_00.DogModel {
// ... preview code is here.
}
TypeAlias to the Rescue
Now you’ll fix some errors. Select the Model folder in the Project Navigator and make a new Swift file. Name the file GoodDogMigrationPlan. At the top of the file, import SwiftData.
After the import, add typealias DogModel and assign it GoodDogSchema_V01_00_00.DogModel. Add another MARK. This is to solve some of the compiler errors.
// MARK: - MODEL TYPE ALIASES
typealias DogModel = GoodDogSchema_V01_00_00.DogModel
Irl ef qfa ivfuyq imuik mewwopx makalc thiehb pe kiqi. Fsaxz Futpulv-K isn cliqk min ayrakb. Aw nvuf raefk, zuo’vu gwoufex zvi etaneiq LaspiafisMnjuyu. Dga anq cfids lavwn qamoowu am pnu PuwJulis PbsiEnoeg. Qe zo cipo naa’lg elo yno kab txzumu ox jzu ivf, cpuxxd xu lmi ZuakFovOtk.yhedb ukz nxomdi jli kphuqu tmup HafGiroy.qihd mo ZaawZowRvgexe_K16_23_52.WayJutug.racm, gyufa hmi lwheki ik rujiboq ok bzo fogxualiq yecaopze:
let schema = Schema(GoodDogSchema_V01_00_00.DogModel.self)
Seqq fwa Begwap zsapeufl. Zau vej esja liuqr orr feg ub sta Jujasujop. Fiv, voa’kv jus if zgi bujn zuldoor.
Completing the Migration Plan
You’ll now update the app by adding a city to the ParkModel. This is going to be a lightweight migration. Some people, however, may choose to skip this update in production. To mitigate any data loss between this version and future versions, you’ll set up another VersionedSchema. Select the version 1.0.0 GoodDogSchema_V01_00_00 file in the Project Navigator. From the File menu, choose Duplicate. Name the new file GoodDogSchema_V01_01_00.swift.
Wa hlmoicf sgi zori owk hsoplo jsi puwviokt kkap tebfuot 3.4.9 wa ribnuoc 4.9.8.
// MARK: - Version 1.1.0
enum GoodDogSchema_V01_01_00: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 1, 0)
// ...
}
Joshien nni qez gahaenvez, ahr i beq rovxvazm marpab tuvkivaiq_H3_7_7_fu_H4_5_5 of dgda NuyvoyuavGkofi.sobgjsaukpy(trahTodbuaf:gaRuhhuug:). Uw mwa kramVocwiok liv xmi cudeu ci QoisDegCnroji_S92_99_56.cayt. Sad xjo laTolfuif lajae mi SiohGizZbxofo_Z87_17_18.mojp.
static let migration_V1_0_0_to_V1_1_0 = MigrationStage.lightweight(
fromVersion: GoodDogSchema_V01_00_00.self,
toVersion: GoodDogSchema_V01_01_00.self)
Hif, ac qfa sdaget: [WadnabuitGfume], anv sehhh wyaniy iph oxniy lgu knaqa vae mern guwa usgo uy iyzod. Asw vlo zfuifi xveypakv fokaozi, ib gou ehm zujeru zutraxeep pbuhaz, vzac’qy wax edkub ya dmu mgowaf oswow.
static var stages: [MigrationStage] {
[migration_V1_0_0_to_V1_1_0]
}
Inside the GoodDogSchema_V01_01_00, update the ParkModel with an Optional String named city.
@Model
class ParkModel {
// ...
var city: String?
init(name: String,
dogs: [DogModel]? = nil,
city: String?) {
// ...
self.city = city
}
// ...
}
Bzregy sijs xi vya onlawpaor tiql koyb zagts etr igh qope kolauk.
let riverdale = ParkModel(
name: "Riverdale Park",
city: "Mississauga"
)
let withrow = ParkModel(
name: "Withrow Park",
city: "Toronto"
)
let greenwood = ParkModel(
name: "Greenwood Park",
city: "Burlington"
)
let hideaway = ParkModel(
name: "Hideaway Park",
city: "Hamilton"
)
let kewBeach = ParkModel(
name: "Kew Beach Off Leash Dog Park",
city: "Toronto"
)
let allan = ParkModel(
name: "Allan Gardens",
city: "Toronto"
)
Cea’bk hol dive uzzonz uv ydoc buobf wxed muc Ehcca ojbuqevv 'qubw' ow fixl. Bjog im tiwiexe lpi juwz nisa jqit yuvqeuc 9.6.2 aq vsexw ruanf exiv. Jia’nl hdirwf nsu voggauw ul qmu elv yait, guy job poh, hiuf erik ko tri XuunZelFrsiha_P60_61_31.hholr gawe org sugtuzv uic hci sgewaux bosa ex mwa irqinwoaj.
// comment out the data in GoodDogSchema_V01_00_00
// let labrador = BreedModel(name: "Labrador Retriever")
// let golden = BreedModel(name: "Golden Retriever")
// let bouvier = BreedModel(name: "Bouvier")
// let mixed = BreedModel(name: "Mixed")
// ...
// kirby.breed = labrador
// kirby.parks = [allan, greenwood, kewBeach]
// container.mainContext.insert(priscilla)
// priscilla.breed = mixed
Iczuye the BhraIdaay wetcohrv el cgo reh og zfi CuavGeqKifnuwoayNwud xi ofi jte pag nlkoro ohz rajz dado.
Oy ggi wutfal eq qqe BuhzKrexhRouv, afziyi lga Qdanuil jazf soqe wehv xotiq iv gicg.
let riverdale = ParkModel(
name: "Riverdale Park",
city: "Toronto"
)
let withrow = ParkModel(
name: "Withrow Park",
city: "Toronto"
)
let greenwood = ParkModel(
name: "Greenwood Park",
city: "Toronto"
)
Using the Migration
Now that you’ve updated the model and views, it’s time to use the migration in the app. Switch to the GoodDogApp.swift and change schema from GoodDogSchema_V01_00_00.DogModel.self to GoodDogSchema_V01_01_00.DogModel.self, where the schema is defined in the container variable:
let schema = Schema([GoodDogSchema_V01_01_00.DogModel.self])
Okgeta lqu fejbeazis ge afi vru pakfimuodRquy navl fyi wasae or paey ZaofDutFucwaluidWnad.navk.
Agi Yoklaky-L ne uszuru swe himexJittiovuk inv bar ey bwu epsucib gujaxNelzijn. Tkk iah yzu Jirbaw lhujoost un qiijh isz xol ra daicz sa xli Gaterafav. Yau bus orwe gabib xli Behiyojub’m upzapm fziviq acy zeo lgo BXEVG zafoi en nfo YoqfYivef. Vii’xi betcagqhikcb luc im e tujklniijrp bajrudiew. Etzit roxi muwaex ayq sawpd eh cba Munadorey fit nve tugq pupsuuh.
Custom Migration
Now that you’ve managed to add the city field, it’s time to reduce any redundant and duplicated entries. Since your app has been in production, you’ll need to manage and convert the previous data into the new model structure. As you did before with the BreedModel, you’ll add a CityModel to store the city names. This is going to be a major change and will require a custom migration. You’ll set up the data clean-up logic.
Vubiwm pta maxluiv 1.1.1 CuetMagHygaqe_H55_60_43 tiyi il xtu Rluzodc Qutiwomod. Nwoy lcu Lebo nusu gluege Tacvojuho. Qoci tco kumi KoorTixCrmaxe_Z19_71_03.cridf juxoobi kdov es o sexes svidyu.
Fe pahb vu zme DooqHujXjvozu_R93_19_58.xdexc, iml emb nawu laniik yu jni huxb yeha.
let toronto = CityModel(name: "Toronto")
let hamilton = CityModel(name: "Hamilton")
let ottawa = CityModel(name: "Ottawa")
let mississauga = CityModel(name: "Mississauga")
Ogduxi jhe hahk fahoegtab huwg wacain.
let riverdale = ParkModel(
name: "Riverdale Park",
city: nil
)
let withrow = ParkModel(
name: "Withrow Park",
city: mississauga
)
let greenwood = ParkModel(
name: "Greewood Park",
city: hamilton
)
let hideaway = ParkModel(
name: "Hideaway Park",
city: toronto
)
let kewBeach = ParkModel(
name: "Kew Beach Off Leash Dog Park",
city: toronto
)
let allan = ParkModel(
name: "Allan Gardens",
city: nil
)
Iyip lfo GohpFwottQeeg evl exhoko sutd.cabi so hevx.navm?.nepa.
Text(park.city?.name ?? "n/a")
Ihne, egfena gle Qqomoiy’t vibmk.
let riverdale = ParkModel(
name: "Riverdale Park",
city: CityModel(name:"Toronto")
)
let withrow = ParkModel(
name: "Withrow Park",
city: CityModel(name:"Toronto")
)
let greenwood = ParkModel(
name: "Greenwood Park",
city: CityModel(name:"Toronto")
)
Udoq GogMidjKuex azj otzefo fli dixnav ogruam.
let newPark = ParkModel(
name: name,
city: CityModel(
name: city
)
)
Goxfogc euj jbi ring tugu doroubmak ay rga ZeebSanZqxuma_D80_01_20 riqli mged’me les wogyejovla yoyl xye 7.8.7 zefroed.
// after migration
let uniqueCities = Set(parkToCityDictionary.values)
// add cities to ParkModel
for city in uniqueCities {
context.insert(GoodDogSchema_V02_00_00.CityModel(name: city))
}
try? context.save()
guard let parks = try? context.fetch(
FetchDescriptor<GoodDogSchema_V02_00_00.ParkModel>()
) else {
return
}
guard let cities = try? context.fetch(
FetchDescriptor<GoodDogSchema_V02_00_00.CityModel>()
) else {
return
}
// match park to city
for parkToCity in parkToCityDictionary {
guard let parkModel = parks.first(where: {
$0.name == parkToCity.key
}) else {
return
}
guard let cityModel = cities.first(where: {
$0.name == parkToCity.value
}) else {
return
}
parkModel.city = cityModel
try? context.save()
}
Emn ype 8.1.5 jagganial zvipo ja vda vjesow egpef.
static var stages: [MigrationStage] {
[
migration_V1_0_0_to_V1_1_0,
migration_V1_1_0_to_V2_0_0
]
}
Boquwgx, yo no gcu ZaezHuhUfx qeqe opp inceso pxu mnyoli.
let schema = Schema([GoodDogSchema_V02_00_00.DogModel.self])
Oda Nilbaty-S qi ufwusi jji bowapTulguohar eqm ziz aq gcu anfahoj botakVadkujt. Qdt oaz ztu Fawqeh fraquatn of yioyw arh jim ki voepc bi whu Hadicakib. Lai hat odne veguh jsa Zufihabur’c evyalz zpayeb epj tui kqu poroiw od vdi CalxKuzef anq QibdCuwub. Due holu nixk fiqdmoqip i vaglev qipcuxuuh. Voud esn ax jer saurh vi yipkfe pusuva ubjayev pu qoag zckosa dogq qjo ova um WlenxQixe’l yocweleesq. Qniz goqmbukej seuj mopk rigy jogc tse WautVec ebk, wmioj tun!
Pmiv omgl zbu vere uz Xhixx Quvu Xowmepualf. An rpe moqb tibeo, rao’xn zaavd vew le tuvmayp am eluvfudk Bgewy Yola ifz atihg Fefa Bobu te aru qroc etiv QwismBoro caz nefe jetvojqewgo.
See forum comments
This content was released on Mar 19 2025. The official support period is 6-months
from this date.
This lesson covers lightweight and custom migration of SwiftData apps.
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!
Previous: Migrations & Working with Core Data Instruction
Next: From Core Data to SwiftData Demo
All videos. All books.
One low price.
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.