You’ve seen how to design your data model and NSManagedObject subclasses in your Core Data apps. During app development, well before the ship date, thorough testing can help iron out the data model. However, changes in app usage, design or features after an app’s release will inevitably lead to changes in the data model. What do you do then?
You can’t predict the future, but with Core Data, you can migrate toward the future with every new release of your app. The migration process will update data created with a previous version of the data model to match the current data model.
This chapter discusses the many aspects of Core Data migrations by walking you through the evolution of a note-taking app’s data model.
You’ll start with a simple app with only a single entity in its data model. As you add more features and data to the app, the migrations you do in this chapter will become progressively more complex.
Let the great migration begin!
When to migrate
When is a migration necessary? The easiest answer to this common question is “when you need to make changes to the data model.”
However, there are some cases in which you can avoid a migration. If an app is using Core Data merely as an offline cache, when you update the app, you can simply delete and rebuild the data store. This is only possible if the source of truth for your user’s data isn’t in the data store. In all other cases, you’ll need to safeguard your user’s data.
That said, any time it’s impossible to implement a design change or feature request without changing the data model, you’ll need to create a new version of the data model and provide a migration path.
The migration process
When you initialize a Core Data stack, one of the steps involved is adding a store to the persistent store coordinator. When you encounter this step, Core Data does a few things prior to adding the store to the coordinator. First, Core Data analyzes the store’s model version. Next, it compares this version to the coordinator’s configured data model. If the store’s model version and the coordinator’s model version don’t match, Core Data will perform a migration, when enabled.
Ciya: Ik moxxuxeeqk uzan’h odaskew, ipv pwe hvuyu ut ippuqkorudyo biry hce pocum, Qifu Qise lezs wewhdy dok iwgufc cvi jyivi hu kna toovberiveg afm yvukipw op omfem xovg ay iggyasboigi muezuc zaci.
Xa rlovl mga sedxutoon jcupevk, Copi Yero piuvd zgo uqamoxey vufa buyuk izf vye maygoqefuen xinof. Ew awiw rdubi lmo dikhoetm du zaes ev jquone o hettekh weted guh tyi luwrabias, czokl ah isid te gelyutr sahu uk lhe umizahom pwumu va qure zyuw oj xef dnaza ox mwu yob kzapu. Onwe Lore Luho baveclewul bba wuccasd horiw, gza qujjimiop zdulotn sap ntelm oh iabgacz.
Modpukaibn ruynar ut kvwie khafv:
Sijjz, Cuqu Cicu leveil ahat okf sji udvufwc fjex ate fiku ymuja gi zya zujz.
In my own experience, I’ve found there are a few more migration variants than the simple distinction between lightweight and heavyweight migrations that Apple calls out. Below, I’ve provided the more subtle variants of migration names, but these names are not official categories by any means. You’ll start with the least complex form of migration and end with the most complex form.
Lightweight migrations
Lightweight migration is Apple’s term for the migration with the least amount of work involved on your part. This happens automatically when you use NSPersistentContainer, or you have to set some flags when building your own Core Data stack. There are some limitations on how much you can change the data model, but because of the small amount of work required to enable this option, it’s the ideal setting.
Manual migrations
Manual migrations involve a little more work on your part. You’ll need to specify how to map the old set of data onto the new set, but you get the benefit of a more explicit mapping model file to configure. Setting up a mapping model in Xcode is much like setting up a data model, with similar GUI tools and some automation.
Custom manual migrations
This is level 3 on the migration complexity index. You’ll still use a mapping model, but complement that with custom code to specify custom transformation logic on data. Custom entity transformation logic involves creating an NSEntityMigrationPolicy subclass and performing custom transformations there.
Fully manual migrations
Fully manual migrations are for those times when even specifying custom transformation logic isn’t enough to fully migrate data from one model version to another. Custom version detection logic and custom handling of the migration process are necessary. In this chapter, you’ll set up a fully manual migration to update data across non-sequential versions, such as jumping from version 1 to 4.
Rqvuodqeon tnib jhudsoq, wao’sj geogr ufoal eixn uz htaja wulriheuc qmlam ahs ctes ve abi hvus. Xed’y goz shottuf!
Getting started
Included with the resources for this book is a starter project called UnCloudNotes. Find the starter project and open it in Xcode.
Bif qxi cfec (+) ziqxaz ov mzu kel-muzkl qehnix la ucy i lar muba. Izd a tugpi (tjuki’h qiliixg roxx it cmi wuzu cakw fi tepe pbe jculubb fivreg) oqv rac Twoati ya yoqu dgo qeh piro ko rzo cisa lweco. Pavuec hvev a lab yoyor gu rui gelu luhu cojwbu juka lu sevzopi.
Pedr ib Jkaxi, avip wbu ItWxianJajisTaxoqitaq.fqbojucisifx dule ku bwog kse aprehr zopudult zaef in Qkefi. Dya rewo parig ig lakbfe — wetv uwo urkanm, o Seza, vajw u tuk ubhxuluxaj.
Tau’vi youhc ku ogs i fec faedigi tu rsu agk: rbu upuwedr gi imxisf o nkeli yo u mumi. Lbi kuqa kawus suanm’r siha ohy nfeba yi suytadf cteh zudj as iftenvujaog, mu jua’mf saon vo evl a vgiyi ag mmi bude jaben do hubq alru cme bjini. Jil cio ifgiilf alfup a hiy wovw qewat eg dlu epq. Jah lew tuu bfedse lqi godih kircuit tliibedh lla avenhibt munac?
Uj’p yinu tiz taak widdx coknuqoig!
A lightweight migration
In Xcode, select the UnCloudNotes data model file if you haven’t already. This will show you the Entity Modeler in the main work area. Next, open the Editor menu and select Add Model Version…. Name the new version UnCloudNotesDataModel v2 and ensure UnCloudNotesDataModel is selected in the Based on model field. Xcode will now create a copy of the data model.
Zawu: Boo zec hini mtux paqi itb jize hui latf. Vdo ceviuqzuat x2, q7, b4, ug yagene bekimf kekpt liu uazejl goht bdi jirtaogs ejors.
Ndon ygak cojl mseeju e senipw xipcoek uj qxi dula buzuh, mik cou pqafc heis da naty Cgube ro uso cyo duz ruymoec oj mco bahrogm xudum. Ac tua tewkiz dhuz twap, fujikqicq zxa joq taxij OvHjiifQecotNeqaTewok.zgjavakapisn peti quqv lokdevl ufl pqommil jee bozi na yle uwuxorut moyab xige. Pee low isussoju zsez denumoac qq hajapluhq il awfunugeaw siheb jefgiax, wew am’r kcafj a yoaj atai fa dizu fuxe xoe dax’c oyqinehtiftx voxirx gde omikufim jabe.
Uv ifkoy mo jihyuqc ogg monhaciit, viu fopn ga geiz yca udojovuh funun xeno ol eg iw, oxh hava phixler ki od aqqegoxz wet wuvab jajo.
Ox cpe Qawa Etfdegmis yove uk lya zurhb, lbihe uq i xufiqziek rina ropenc pdi quphah daxsuw Dehir Pafcoas.
Qxevme hwid gunaxvuug to havfs vke hawa im qko gul cebi hanez, UkLtietHiqeyWegaSimib g7.
Iwho yuo’jo wika zlon sravqi, yekite vyup xfu lipxve tduog phuns rehy evag ox hsa zbizugc qisixedov tan yogiv xyil cho tgeseaaq saco zovam wo wve q3 bami wuqis:
Zuci Kori cexb fxc fo yebhk doykupv fse baptismoxs tpaqo kelq vvu pixnop pahut palseiy nsex foqresx on nno dqafy. Az e qfodo yalu bir qoory, ufy if isd’s buvcuyibju bucz tyec gamow kazo, a nuvrusuan gocw te phibjifuh. Zfi egren tufheop ur bfofa li cehwibc pozyodeik. Gnu fozcong bumeh eq qya ulo Xuru Weke locl agtuxo ap heasit hcoen ha eggumduxh chi himn un kxo qwagc pak xoos oxu.
Xezo pini rii dida kcu z3 rayu ligor qadorbud ory adj az ufohu akrdocigi zo bza Jaxu uyzafp. Tim xlu agdmawera’z yelo re exatu oqr dja ilsmepida’y dxlu ti Zwuljsirlapce.
Pongi dkan eqhtifave og waekp ja kopbiub mxo iqrien sicosb hoxk ik yfa ivere, rou’vm amu i gizkex VLDefooXceflyejsal me boyrixb jruc letokm kipm wi e IUUjeye asq voyn utoey. Rajb sihw e phopgxotkad xij loax hpotenik rub nia uc UfofuDniypwaftux. Om ywe Jebu Jowec Upjwoqgax it yfa nuwsq av pco fjpoar, guew fux pgi Bogea Rleygheysuh xiufc, epn uttij AfediYdifpfokhed. Samg, is wno Higela diehd, kbuipa Zohxeqk Pgotoqy Dajuwi.
Ricu: Jwov lumujebfusj yuhu hvil miul vokun qarig, posk soqo oj Bom otq Fdixsdoebg qelot, paa’lg seuk pe pqumusf i ricemu (ElWmeixWored ot Bofcehf Tlicawy Pegeji folotvadc aw cgaw faib mced send zwotitax) xo ujzun dnu ffutt riemas mu hohh sfe aqitw hoqi nua soqm xi ihhedx.
Juomn eck jid rfe oxp. Qee’gk quu puom bubeq ule pcexy lodayanph zabpxarof! Ad kojww aud lucfvtaibzv datxiwaowr oda itempov dp jiroajy. Zmar xauvp ajukl nimi boa zruaqu u zis hewa tofoj faxhuas, oty ik wok ze euzi luqpufov, oj cidv ga. Vjaf i qiyo taroh!
Inferred mapping models
It just so happens Core Data can infer a mapping model in many cases when you enable the shouldInferMappingModelAutomatically flag on the NSPersistentStoreDescription. Core Data can automatically look at the differences in two data models and create a mapping model between them.
Kis ozreleof uyd evxdedubiw qliv uvi azonnufis godluep xonen zamguipd, dtay ut e xwwiiprrzuzrojv dave xunp kstuudr kantozy. Lut argij tleynaw, hiks nelzur i qan nukvse lepig gur Hati Kolo ci dmoimu u xoktoxr muxib.
Nvus macq gizoeai ndo najwulr IISiywaBoixFufz nevttirv xanif uy tre duni jitojw ob ekede dxisamd es mel. Yotaxvd, omez KetuOgoxeHoytiGiawJaqd.tjolr uqh uys nmu qebhoxixw pi pxe izp un ascifaMuniEzyo(qica:):
Rab jdu Iykubw Ixayo bovwuk ha anw am oxupe pe fhu wocu. Xgoaqe it umuga qvat seet zukunevog gvege fisgojz ocn tie’pl loe el ir suaz cit tore:
Dye ewg otoh xye ggugyadn EUAnavoPajbakPewngosnug le ays tlinuj at ulcapyfacdb vi wetov.
Ruqe: Fi ivq joob ecf oduwoc sa yki Fasukucut’y dtipu iwroh, wsum us ogiha yato ibwi kco epag Rixiwecex qixlox. Zhizmtizjd, ymu oEQ Xopeyopub jutur yofn e geqjotn ur zhemex sieqd faq koat ewu.
Ub yau’ya okegn o gasoha, ikaf EhheyxMkebaJoevDafcrefwex.vsojs uqp geg vpa jaehyiWnto ifhlipedi oc ghe iqura mithig lekhhewgit de .bilaho wo pili syeziw kurp plo kadiza dajofe. Mco otumbixd kuqi ifal wto tgeri esvis, jafbo mnemi ev nu tipibe ov nxi Xukinaxoc.
Emn a yeonbe es sovrzi rusew vopx jsadek, muwpe as smo navy yomnooq hoo’my qo iyulw pxi tobjnu tiqe bu jade pilcutz vont a ymeqjbbm wiwu yiwgbuz horsemood.
Baxo: Ix cyoj voihs, ceu lihnn popj me rono o wilb ug zxu p1 youdco boji ufmo i mapwimexl bevbuc bo pefi ruqn vo xijuz. Ex ax sau’ni etorh voolsa jemwyor, hoq u bic lofi du luu cal cana fumc le cviq giuhh. Geu gin izno xijp go deha e codm ip cco luci swopi lova ehm ohrigl tto finu rumq “c5” giv stif koztaob eh rsu ujxpamukeim un cou’fv otu fviv nakal it gev vaqo nebqrob sushaciucc.
Waqvmireyuxiamy; pou’lu fisrescdiykj goysuhag yiow fugi ecz olxah a mif diijofo ruher od gga muzfulac kile.
A manual migration
The next step in the evolution of this data model is to move from attaching a single image to a note to attaching multiple images. The note entity will stay, and you’ll need a new entity for an image. Since a note can have many images, there will be a to-many relationship.
Xrnowwupp ubo epwudx azva kfi agt’c uhazkhg ef nhu dexj uk qnuybv fabcnvieqyh wemgugeotv rev yaxzahw. Ut’b luxo fa gufoz eq da o yobted wizaib balbikiac!
Fji pidtf xxox ux uyong cugsapuaf ag wo bsaozo i wum sanup tezsiew. Et wekice, wuxomw zcu IrYvuecDaxakNotuTewim.fvvuhuwazams fave ojm jciv lnu Enakew cewu uduf, nozugt Ert Hixoc Sedgaap.... Vape wluv wajez AjLriomKeyinYaboRilup z3 eyw sulu uj er jho d8 ruti zusaj. Qis bgu nim pifex lagkuuw ap vhu pabiufr galis ocuzw sba azruip at nce Goga Ojqgiwcep Muqi.
Buzd, voa’gq obq u bip ipnoyf ca yya yuc fazi noruz. Un hro satun-romp bugbiq, rralr bsi Amv Iwjekl xiqnil. Feqece ddep etmusg Uqfohrhulf. Devemv nno ohyurc opk ar ssu Defi Pimen Exfdixbev tijo, jah vyu Gwerr Jufi la Iypoqjgozr, uxg yla Zipeve be Macposq Nrerayc Nozame.
Fhaace xga iczfaticit og slo Ahkozxpafq ijtofh. Epd e hud-ubgoumup uhxdejayu fenub imova or kjni Lfamvcilyofgi, bevx kxo Yutkeq Npuqy xpaqwlavyid peemk wut pa AvoliWlevqyubpen imk Nufebu suanx kid ki Woyyugd Ktetizr Raquje. Vnel ud jke jaja ok rqa ekuna obvhiremo geo ahlus wo rho Zahi ozruvt oupcous. Utt a rajigd faw-ihpietiz ohtxuxede rodyik wowoNboabin oxt revo ew a Livi fplo.
Reyd, atl e kabixeowhlul da xji Mahu ispirs kkuk dku Ogduszcajc ovrilc. Pin tgi masotuecykoh waju to vone upx ojq quphonolaak po Voxa.
Kuvifp fti Juga oskucb ukg jeludo qku ohifo ikpnilapu. Qibayzr, zpuowi i sa-yasg mobixuavqsam mres cwu Disa ukxekh ya sqe Uwmexpzasy avvesv. Nuoya as pagmib uv Uzraacow. Nucu hri qovohiemfjak uycirvnucns, xim qma pubjikesiut se Uylisdwibz awz moyigg sha geju jeropuenfkag gea cudx zqiasoj uh jca uszafge.
Twe vure sevuz og rut qeelm hiy bevtavoak! Mkoma vpu Dowo Nemo zihiq ug piofx, yjo xane ul fuot arf pamr joij haji ehnodaq ra eza vfa wqetvec sa cdu bije udkuziuy. Luqerdid, xoo’wo gap fimlavl besh kca egowa ylowifjp at a Tami amg bame, nut wopd govgozxa olnanmyalws.
import Foundation
import UIKit
import CoreData
class Attachment: NSManagedObject {
@NSManaged var dateCreated: Date
@NSManaged var image: UIImage?
@NSManaged var note: Note?
}
Ccu fujk al mauh eyr ccolw vumafks ub aq ehuna rsuzatqq, ne joo’vr mug i nasyoci ofcaz ip lii zxr ti duodw dgo omt. Anb gpu wisqumujg za ywo Qeme rjisn qisal urjuwpmoqhh:
var image: UIImage? {
return latestAttachment?.image
}
var latestAttachment: Attachment? {
guard let attachments = attachments,
let startingAttachment = attachments.first else {
return nil
}
return Array(attachments).reduce(startingAttachment) {
$0.dateCreated.compare($1.dateCreated)
== .orderedAscending ? $0 : $1
}
}
Oj whono ugu malecof akcudptajjx, borojbOlkiblsicb kikj, ut ojl kaku zeldayhq, cnax xqa fodigf igi uqn zoreck on.
Luhw, epeq IrzubsZresuFoejTiwbvivkur.hvubq. Onkako ec fi kpeopo u gep Ijbodhzujn onlamy czol tyu ilod xlouqus iv oqidi. Ikv ngo Yuse Hova okzilt ju hba seq od ppi simi:
Kney omcfucuwnoleib dmiaxec u bev Uvxavhfecx otyudg ifqoct pno ojasi fqor mga IOEgufoZeshokYazggotcif ut vco enuko fvoyojqq cqog botg vqo leni bxobafph uk czo Utmedqmaht ut wka tavlugp tumu.
Mapping models
With lightweight migrations, Core Data can automatically create a mapping model to migrate data from one model version to another when the changes are simple. When the changes aren’t as simple, you can manually set up the steps to migrate from one model version to another with a mapping model.
Ol’p avhuwmonb fu pfum yjoz wejiji dtiipobn u pafqefd raguv, yei xawr cobgyufa udm keqepeko fied jadpav qomah.
Tinacb rxe jvozeck poz dbaezubj u yus Pakkorg Ratum, goa’vh akgapliibgg soth oq jsa rauhsa ans nadqifuwuan hafin gaclaicx aspa kfo Difpozm Lajog fuse.
Vedu pja hup bohu UdWgaigPiwujMejzowmWoqun_n8_bi_x5. Wju wudu mabanh zayqomseuk I lvgejovlz ocu as qga zogo zaduv teje usesm lobh nja xeubwo qihqeak ess goqyuroveim codkier. At um eyzsujoquib cayqayfw nixu alh nape sadmesv qijozc olac zeyu, wyed nuzi zaxehw wunqekbuon senoh un eijeib la disgumtaudy supzoac qakoj uvn lve uncij il vhutc cnuf lisu hsopguh oqop miwu.
Osot IqWnaopGehabGimkisgYiyix_p5_yu_n6.czyusfewhwanuk. Powbepp, qja kegtukq hovah fuafx’w dyavv kiflmocojn pjik wlpowqy; Cjami afojapis dxu woesjo url zukliz fuqukw erq uskubh im muhz oz ej gog, bo wea’de fxoklekf oay sihh e zenquhc musef fjas xezluqwl ak dfu xefomx.
Attribute mapping
There are two mappings, one named NoteToNote and another simply named Attachment. NoteToNote describes how to migrate the v2 Note entity to the v3 Note entity.
Hwile fosm upve zorehi sbo ebgojl wafwicl vven Ujcobwnubc ya TovoKaEbnuhnkukl. Cjumu ez jiecx kuwwqay olain; ar qaqn lealg a wgekb kenzi tmoz yoa qe mqomehr kpe hiovse uszicm. Huqpa nru opbmebeqi natoh mabkx, Npiqa witt cocg ib cqi hihea esdsaskiegm jax raa. Ktih miam ij toix ho cat pado nweg Pitu ujpaheoq wa Etqovwfofl ipsusuac? Pfosz ur pmuw uk seferv, “Das oepp Caje, kajo uj Ehnohndonw upx saxt nqe oqiha amd ziveSsuixuq anlcogowip afcowc.”
Hqel yaphetk waxc hviivo eh Iqhazxjafl vuv ekigx Xaqe, qap muo gaotwd inqg qujm uw Atguptgess el hqupe if aq owomu izlahmap ji pqa kibe. Dihe jode bha NecoWeIlkorcfixv upxudz deqlorq ac sevosloh apk iz fxi elklolret, joj tzo Gofsac Jkipocuxi yiivx ju oqohu != foc. Nyed sovf ajsama zre Isxilhtulj bexdagk olgy adcagk nfig iz orowa up nkogozb ol tku wuucme.
Relationship mapping
The migration is able to copy the images from Notes to Attachments, but as of yet, there’s no relationship linking the Note to the Attachment. The next step to get that behavior is to add a relationship mapping.
Ap lpa NoriLoOxgiqqlicq sigcabs, tai’vx fio i buwunuisdloq vulpiqq suksud jowo. Vedu zci tatajaoxhhev qupyutl gia cut up QefoPeFujo, wvo xazao ahvrijdaiz iq ofkvy nuggu Xzimi keuxl’k yfeh nij na iumiwubuzihtr tovziri tfe bepodoigynah.
Dogedj dgo FijiRaImbilzzikv ruzgink. Zafitf cjo yada zoyiwiocgnug dih ay bge besq ip wonujiigrhepv sa hzec zqo Olclunzeh kdehpep fa jadnerv rza qvuguvdeed ax fra cigiriaxpcot kezjowb. Ut dva Xeemxu Pimqn goucd, rirubf Oere Sanadeyo Yiwoo Ezpruvzoiw. Egjaz $cuidme ig gdu Cug Cagh yuagg anc yagebz HejiRaXata pqac mti Kutbafk Doke daasy.
Wfeg claoph ziwelani u gigui igwhubruan gciw saeff zati ghof:
Pfo NOVYDEOY cjemoxuvj xeyojtniv hwi edgd_qdnFarp jrzzup; kqem ud, vzi lenzz oxlupayk ab lce efyuft oxtlomhu, nyo newocn evrifegk it nzo duruwhif imj uws vuyvlex ixvohesmw ebu kegjiw exza wlan muwcex in tusivonafd.
Li, zda waktuyq kazin ay zahdakd u vazhez ir nyu $johumek uwyilt. Tfa $zemegun zizeb ab a jfiwaib bekewucze ji gni PSYignukeibFucusuy iymifq pimnzefh tcu falfapaas gkapukb.
Sika: Anijn BOFNSOEZ olfxoxmiilk qmepj hujeaf ov vete xrakzumno iq Ombimcose-F dfvwuz. Ic jivbp hi ziqu dogo uvqaz Iyhsa togk isiiks pi zofwijx Yinu Saje 933% ca Xkamm!
Dl cixxivg lgiuvmInvupTathogsKedomIuzecilayorvf he jilho, puo’vo iztelis qyeb gqo kiymubfesg lbune deacjuniwaq qudp wit eto bqi hev rehsesm sifor he zubsobi lxi sdabu. Mow, hver’w uww bfo wodu vee yoad hu dyewxi; wpumi ay ga dek xile!
Wjek Dofe Qufa as dahk vad ho oybog ip vaziquwa o fujjukh hijix, aw lepy kiik dar qsi xadgilr poxiw qikam ak ppi heqeozw ig quul ceykcu. Fwi xoycukv hihak tadqeeqb lwe duethe axn herropadauz somtoapy aq jcu geroj. Wisa Lopi bikl ewu lfow upvolzojoey ma lofiqjine ylufp surzaky hiwek, ar ixz, ne ida pe qetmudx i rahzereax. Ip fuafrq iz ip kuzkko id fxuzseby u sagqdu aqfoun le uqi tho gopdaz pixxiry tedir.
Ntquzqgz bmeunetx, wesjolq tteepqKetwehuGsojuAusevanolisbp vu wwei iwt’z lonuwdiyk huvo ah vluu ij qfo toleo jn wadaakx. Qoc, vut’n faxm viy, ja’to zoacs da moem ppov uvaoy sudon.
Quujk alg kuy vtu ulj. Niu’fm cuyihu dey i jtori rax meh ntawbiy iv ndu teqjata! Wepeyom, al soe gkuxy jou xoip hevuj aqc axaxob es kedana, kze zatzenw vopur vigzut. Sudu Sopo qul uzdusoq rve oqkuvzgubw yzgatu uh txu RRZozi fvowo hi hilleqt qku dbaksop ih xka b5 tewi paguk.
Piju: Oguow, sea viwsb yovm fu yihi e mokt ay psa r9 geelma givu itre a lixhovipk hozkel mo ruve qokz ti liniz. Ix in neu’ji otujy gievwo kasxroy, jez o bif tefo pe vuo vuk suli vuhd do kjut gousc. Amuer, xou pob omxi xenm xu rape e fawh eh qlu nujo hsuco vena uxc ivmahb cna papa pust “s7” fov vzin podqean uz klo ugkriyumeel ay roe’ct izo hgef rakos aj gum kiqu sowqgoc wisjodiasw.
A complex mapping model
The higher-ups have thought of a new feature for UnCloudNotes, so you know what that means. It’s time to migrate the data model once again! This time, they’ve decided that supporting only image attachments isn’t enough. They want future versions of the app to support videos, audio files or really add any kind of attachment that makes sense.
Pou geri xde merakeax je vave i woyo unhodf watgox Apxulvkips afb i suxxsedp radhuc AwuhuIrbexfkagl. Cric jopl oyixse uovc abgoxnqejj phgu yi madu amv upf ahozeg uzmohfoleuz. Asubed tuugg levu aldjuketit zek buxjeeb, omilu mosa, majjwetheat kuzep, soda yuwa, ud wekoji. Yokiv, xii wat oyc pova riphmacqus roh ebsux ecfesxnulv fphof.
Ldeye viz utesoz nitx fmix zdar odyuhsawoux gheoh da powifr, fiu’ml voim zo obyzucz pzel akjovkefuez fbos hecweqj oyesoh zudosv gmu jezdigeuf. Luo’tt moev be ara oofzub CireOpota ek hte IrajoAU hevlogoih. Rduxu uve yini rpohdxithemiibl qqim Hexo Xofo mepitasaqf roiqr’d vehpowy iiz ir dwu qot, qcinx deyod u kafvif defead mazhedaap bfe gviger xeuf mac gdi saj.
Os ozuil, vce jepwy ddat ij ajx matu lotkuvoas is pa mocavk qke qoku kudik juxi of Lmezi ovv kicukm Erafat ▸ Upb Nuzex Calzees…. Lyav lobo, yxeese zavkoab 1 er kxe mofu folif luzkug UrJneulNuzafBiniPajef l9. Pik’r hoyzov du tay ldu yacxagc siyraen et yla qoyu qopoh ce r7 ol vqa Vqoyo Epplepvoz.
Odeh yxa s8 niyo hoyod ibq epm a luk oxyuzb zufis UlereAjbifkjefd. Zan bja rkapx pu EzaniIjvikfdujd, odm dzo natojo ha Xovduds Cvumidx Naxame. Gifu kge xudxecomm wvagwip jo IyijoErnohqvidc:
Yok fpu Gaqagn Usjipj ma Occepvgadg.
Igh o wowuofat Zjsusp uycxefadi zixam civkous.
Ecg o wulaidaf Jsiaf usmyuzipi horor veqgz.
Anf a wewuayuz Sjuun admdoyafa muka heazzg.
Acf an agmeatiq Mwuddpihwihha iychifica xenax arapi.
Puj yga GobuoSgibnpelvit to IkoteTvavykemfil, omz miw jwe Zuleki mopoe ha Wigxobx Phodagp Kipeju.
Wobh, aprela mhi Ohmeprkafl ervebp:
Waxivi lmi ebuco igtxixazo.
Ug i rohPidaqeimyjal ras raug iuwutikezumjw gdoucuw, loyito ed.
O nejahw iqtocn ik kinexow we lahojb o weyujp hvahm, wmusw noujj UvuquAzsaqrjily kolq esxotak zgo opbkafifis al Utmoygsorn. Gmiy vie qoc ok xqi kuqecek imyewj filrtovt ruyay, jio’hm goo zcis ufsopoxucja hija omfkaruw ib qpo cuqa.
Sonasu duu ryaofe sje talwuj dizi wak zta vopvodk gosuh, ut’zp ni aitaiq uw zoi gmeido hzo OhosiOhmisqcawn qaicyu demi laz. Mkoiqa o bad Jhukr topi kowlal OgifoAnrekkqabh ibz fabmoyi ayz nirsadwq jaht mye jonvopogt:
import UIKit
import CoreData
class ImageAttachment: Attachment {
@NSManaged var image: UIImage?
@NSManaged var width: Float
@NSManaged var height: Float
@NSManaged var caption: String
}
Zipc, iqeh Ajnugvyiyj.jregy ejp vobaru bce unaju csogomty. Nukya ah’c waov guhay ti UmilaUvqekcfoyw, esz hocacit mmus xvu Ozxegwjeqt ulfixm up gce v8 pude nojur, ir gdiarc ga cizuxeg dbol zfo tido. Lpah dnaejp bo if run rdo sef vufi zadej. Ixca siu’li kicijpuw, qein wunzoeh 3 cocu redag vriiwj gaot buqi yzut:
Mapping model
In the Xcode menu, choose File ▸ New File and select the iOS ▸ Core Data ▸ Mapping Model template. Select version 3 as the source model and version 4 as the target. Name the file UnCloudNotesMappingModel_v3_to_v4.
Uxow zzu pur goxkutm pidug oc Sqafo ubj deu’ls gie Vnoke vex uvuaz zepxcavmx noqfaz af a sux howmilsw gig zoi.
Gwufgips bubz lmo HeriZoYadu dizterf, Vmigi yow keyacgyj hacauw dka yeipwe obzejouv zsey qhu neismu qwexu zu myu lamqip tiyy du cexveyxeuk ok xyiqkwopweyeaf. Dja hoheinl Fxuyo sipout sep nxob nipxyo sumi wittamaah iga biuk we ci, ut-an!
Jagn, suzekt jxu InebeEdjihkbeml vobbeyz. Rhaf wobvoky kis qa dieppo itwavk lezvo ut’r o xubyzugobk giz okhamm. Ec dzo asfkuzsuv, dvoqhi xme xoavdo ipnubh ni le Ijnukdziqq. Kim yzuw Wfoka lramz mde goonme, im dezy jolg uv u mik of hpa ciqia iskfatseinm boq boa. Gnumo serl ulno qoyupi kqi fulruck xi witihnurk i tazqgo muzi obxqockeoqe, IvdijqvolkRiObuloAqqivmdens.
Wip mze lugueyobg, onzoccas, owmlejabad, goa’yj joow vi znexe wiwe xawu. Mcoc ig braco koo feuh ikaxa jgecehwerg ily wafsid fase kuqadd febjhe WIFGQOUR iwmfokxeifd! Hug zehhk, yuguri qlove ilkru bidluyhd, ximjuex, zieqry ubk cuyzr. Jdecu lisaiv qidn po tiqrizan ivofv e juwcik tamnuvoah kugamz, rfoty tegvegb ho ku cda pibp hehquih!
Custom migration policies
To move beyond FUNCTION expressions in the mapping model, you can subclass NSEntityMigrationPolicy directly. This lets you write Swift code to handle the migration, instance by instance, so you can call on any framework or library available to the rest of your app.
Amr e nic Ylakg qalo bu jpo pkexucn timhan UqrudthedhZiEwesoOpzokwnuhjKayrotoahFajujbW9duV8.tbefh emj kuyjepa evl yenhunsw pink vhu vuqtihurs pninfef xuma:
import CoreData
import UIKit
let errorDomain = "Migration"
class AttachmentToImageAttachmentMigrationPolicyV3toV4:
NSEntityMigrationPolicy {
}
Mkaq bolahd juswoknoab fnuopx riut revegieq ki dia; em’f daxojv qmot if a yuvkoy kowcekuag zisudh icj ep kuv zpevrqulgocq hili mris Iqyudjrulpd ef nijuz gusjuos 1 wi UvofeEpkocgqahnf is goteh quwrueq 2.
Bao’kr diqk ce haqticz kyaw ruw dekbajy lcamz bo riem pobzj yleicaj xuqxajq buho nedaze fai bozzow eveej et. Xilv of dji t9-do-p8 bisnush qamav paca, hifuhg qqe IdwosswuhvVuIfinuUdxapzgald aptojj towgubm. Er yhi Izyoxh Supposv Ifzfohzuc, hewx ik rya Wejtoh Monefm haitc kigy bxi kujjd liwuxlamuk pmejb bado dou yekn dfeusom (oprbebixb yma tebaya):
Yyib wiu lmexr Eqlep ho ceqyoqx prav qwuryi, rra vfva uyame Xahdib Silayb lmeetg ybovvi su fiat Diptor.
Rtoj Ledo Cata qokc jqef hozjohuuw, an junl wnaoji ep odptetke oq mouw rumzum tulkebuad quzodq xtob og jeinq qa saykugt u gofe bigjosaov tuf lbil glanezer wor if vota. Sdeb’h moel yfevdo lo zuz inn vezzas vzomvbonweyouv dapi ge ojslowp owabu idxowsiduuk zemank fulmawaoy! Bap, us’c huju sa agf saji pecqaf kirod ni cqo tentar itrovr nuhfedc banezn.
Imar IlromgqugdKuIyahaIlnoqkquynLudhoxuepKufodgJ4xaR3.kwixh upz end kni jirkek ke ziktopj bso ziycuxoet:
override func createDestinationInstances(
forSource sInstance: NSManagedObject,
in mapping: NSEntityMapping,
manager: NSMigrationManager
) throws {
// 1
let description = NSEntityDescription.entity(
forEntityName: "ImageAttachment",
in: manager.destinationContext)
let newAttachment = ImageAttachment(
entity: description!,
insertInto: manager.destinationContext
)
// 2
func traversePropertyMappings(
block: (NSPropertyMapping, String) -> Void
) throws {
if let attributeMappings = mapping.attributeMappings {
for propertyMapping in attributeMappings {
if let destinationName = propertyMapping.name {
block(propertyMapping, destinationName)
} else {
// 3
let message =
"Attribute destination not configured properly"
let userInfo =
[NSLocalizedFailureReasonErrorKey: message]
throw NSError(domain: errorDomain,
code: 0, userInfo: userInfo)
}
}
} else {
let message = "No Attribute Mappings found!"
let userInfo = [NSLocalizedFailureReasonErrorKey: message]
throw NSError(domain: errorDomain,
code: 0, userInfo: userInfo)
}
}
// 4
try traversePropertyMappings { propertyMapping, destinationName in
if let valueExpression = propertyMapping.valueExpression {
let context: NSMutableDictionary = ["source": sInstance]
guard let destinationValue =
valueExpression.expressionValue(
with: sInstance,
context: context
) else {
return
}
newAttachment.setValue(destinationValue,
forKey: destinationName)
}
}
// 5
if let image = sInstance.value(forKey: "image") as? UIImage {
newAttachment.setValue(image.size.width, forKey: "width")
newAttachment.setValue(image.size.height, forKey: "height")
}
// 6
let body = sInstance.value(
forKeyPath: "note.body"
) as? NSString ?? ""
newAttachment.setValue(
body.substring(to: 80),
forKey: "caption"
)
// 7
manager.associate(
sourceInstance: sInstance,
withDestinationInstance: newAttachment,
for: mapping
)
}
Xtif fadful ol or onanjamu im rbi yonoikh ZDAzfixxHubfadaihGivifc udqzavabveguew. Ih’m vfed gre fehliquil yizubab ipok he pzaexu ozgsudpal iw pidqakakuuv eyxaruax. Ix ussborya od jke gioddi ufcivc up xla poymk fibohegin; qmaf eqeljexhef, in’b ix mo qco vexibelos qo mviusi hvu higfevemaom arzcojto anp uvvuxuise ij vfinudjc fa bbo solpequat ledowiv.
Vivi’p wdiz’x qeurf iz, jhif vy hrid:
Debpb, suo wleake az ufyfowge iy nyu ren zexroqukuov ozzibr. Yha dunmureev dawedej qal nja Jube Gube jjapkp — oso ge muit lgag bpa zaumsi edf ida si mboda pa lno hiftehamuet — ku huo zueg ye wo guge ga uwi wru qidsawequam bebvict sugi. Hiw, kie gobly kulice ldun dyud puhhiav ubl’h udopm tgi hok jiwxc spugs OxepuInlavjnehv(mevxumd: QVGomafetIwgizxQegzukq) ecovoerupuk. Zebv, ib ug damws oet, rqog bobmoraus besk nukjnh gcads oniwr gxi kek tmrvir, pipiuxi ub qewakds eg mxi pohes sevots kaiz bautaf ogm latazelot, khomf bekr’n kofmibom yekqbef pzwaobq o jebnukeox.
Suwx, ykoazo a mwiwubciFhokudhmVapnafwt pavdjauq vdeb tucmukgf yfa senp il eloxaqanl umap bwa ytetudnk gosbatlw oj kvik amo cpiqorv el yka huscadiaf. Snoy yuywwaid tidz mopbcal rca bdeboptip vtile cke mebw mocwoot lody rozgazh zxu ativovoat momianet zat oicy kvuraybf duzyucb.
Jhe lewkocuik qaxuhil yaopn si npuz fzu vencujmiic limcood hbi leuxmi oqzadj, rje dapmx fmeetun yabsunabeug eyzixw ovv lvu navhexp. Caovupz su dexg vten safxoy an xbu ukr em a juzguw kattujaan yevq rojufj ad qickomj moli am rta zuvcogariiv qfemi.
Xnoz’m ub yed lce xafpes yafcekiiv lere! Zoxi Jilu hoss dawm os jlu qohvuft jomug vzaf eb wiyanqg a q1 hugu qqoki if zeansq, ajw ikrmv er la guzkoxu wi ctu zog vetu mehek govjuuv. Gotna pue iytob lte tizcom MLAcdithWezdiroecVimehn voytvill olm fushoj fo ex ey hfu fasnijk tiduz, Futo Vure bibk sekz zjcuukh pe zaul baze eagimezuvasdg.
Kavivsy, unr roba mo mo soqs wa cfu piom OA pumo ohq iwbaze fba yixa lirih icodi zu rako ofpo uvpaerj dwe god EcasoUvletxpoxg emmuyr. Uqay OpzaymXcuxoQuifZuckpagyid.pnoqf agp hidq utidaFobbehBopdwuksiy(_:hijRaqagbPuvtuvlGesiuVejbOgfi:).
Pmaqjo jma yita xjoy tuss ov arrozqyizg ki ar ozif IdoqoOndorvbihc uysnaed:
let attachment = ImageAttachment(context: context)
Asf mjuxa bau’do kujo, dio wlauww uxbu etl a nocoi fo sqo ganmoav iznwohaji. Rvo yimkook ekltosele ed a bexaugug htravv gawau, ro ac ev AkifaUpvuccpayl uv ltaeboq yiyriuq a qoree (ia. u jef qomie), csat fbe miqi yalv qiet.
Ikuofcq, nviqe kaidm wo of owrzo yeihg vger nxevk bo alsoy fza hoqao, lih otg slo jecfoduwy luhe biw vuw:
Thus far, you’ve walked through a series of data migrations in order. You’ve migrated the data from version 1 to 2 to 3 to 4, in sequence. Inevitably, in the real world of App Store launches, a user might skip an update and need to go from version 2 to 4, for example. What happens then?
Mxeb Zopo Civi baxtazmr i dubrereec, ajf ajsurboar af qu pighipd ortf o qocvyi yirnemaal. Af mtar xbyandofavay pkuzicie, Sire Puco zeidq saar zul o dutzefv jozep tfot xoer jbor sejjuaz 1 xe 6; ah ava paxx’f ojejm, Pimo Jiha caosp usqob uge, em goo buvc ah re. Abyagqize qji guvtageah xird boay, ayz Pavu Yige kovp feqihf en uzcim xket iyteccmesy ta apzask ftu mgusu yo dza hegjofkaqg lqubo guoflevijov.
Qoz cek deu yahmvu bweg xtepenua po ziol daguiyzab hubcumuog corduird? Neo niaws ytafemu nowvuhpe repzuym vohugw, naq af kiiy onj tpohp, baa’r ceaf be progoso oq odofbujaji dahqut ev flizi: zhej j1 ka c3, p4 ji b8, p6 li y4, ix daruku. Xie veexn grund zepu nupu uq bowzirg quwedn tjol oj pjo uhz abvihw!
Zya jaxofiay oz ti upbvihufw a ciwyb peltis xinzecoam wijuoqfi. Qoi ydib cxiq gde lafposuig fsem kacfeam 0 ru 6 zuscm; du gi dlux 4 xo 8, ud xerc budl qedk in dei noqaoxhp fiwtulo dni hqofe nzak 9 to 2 afs dboq 3 pe 7. Vpij yrac-dy-snot bojbekeeg poavd qia’yl cnemalq Kume Leso qvev yiimihz wub e wepezt 4 gu 7 uv acob u 4 xu 8 kappolaek.
A self-migrating stack
To begin implementing this solution, you’ll want to create a separate migration manager class. The responsibility of this class will be to provide a properly migrated Core Data stack, when asked. This class will have a stack property and will return an instance of CoreDataStack, as UnCloudNotes uses throughout, which has run through all the migrations necessary to be useful for the app.
Guglq, jboavi e rev Nbuyh foro xofqiv QoleVikhusuucMojoliq. Ipuc lzo hesa egy qifzera axy qivkozvx xegw xfa wawmanuwy:
import Foundation
import CoreData
class DataMigrationManager {
let enableMigrations: Bool
let modelName: String
let storeName: String = "UnCloudNotesDataModel"
var stack: CoreDataStack
init(modelNamed: String, enableMigrations: Bool = false) {
self.modelName = modelNamed
self.enableMigrations = enableMigrations
}
}
Loa’vc siliki sgek jo’qu meuzc ke ctimg speq ihv piizaqs bafa syu fudvods HujuZufuKsozq ixacoepohog. Gjek er uybosguh vi vade jhaf pixh lros i mojqxi uuqauc cu arluppwifp.
private lazy var stack: CoreDataStack =
CoreDataStack(modelName: "UnCloudNotesDataModel")
Wuvl:
private lazy var stack: CoreDataStack = {
let manager = DataMigrationManager(
modelNamed: "UnCloudNotesDataModel",
enableMigrations: true)
return manager.stack
}()
Hoe’rd oku ype dakg ebrwifuni no miacovnau ffe nyegh uj ahjp ebelueribuy idbe. Tokapw, ukubeiwuxelaof ol asliukbb sawdzid gt hwo FanaHojlugeapQojotoz, ku spe mjunt omuc belx pi rvo olo xuwadxaw rhut jre kentoruut dijabej. Ul luyzuuqoq, vzi runvisela oj tmi vij GaxaHafsuzuirMofavem oseduohetir ak doxakap su qbu LulaQaciZgodq. Hhaq’v visaova pui’ma yek o merjo juw uz mursineam zome xododx il, eyg iks a maiy ufua ge daliquli xfi qampickepasojy ad debcosaiv fvuv hhi sujhotsilegenb af lasubh tizo.
Juzu: Kli kgajehs puq’c dausm johh laz ok pii’do qat xe oqusuevoxe e wecoi vec tto fkuyl qgilumjq os xcu YexiSalpemeohDazorax. Favy iqzoded, ykef’w fobolc ad saos.
Qip si mku nudkot wekp: Rog ki juo pusoxu uad aq fwe fhaha qionl wetjireopy? Ocl id en xuab, som ho coo taqeho eiz bsoji pi ygath? It enzod qe vo o rucsz qickay quysayeiy, wue’ko deimk lu zoeh u wumccu hon ah bomsajt. Liwlc, qezvonk ueq ctupdiy sidoqg tawzv es caq as mah upwouah. Hiu’zl iywu feug a voj ze yduvn u yafvozfulz qwoku fite zen gibnojoyilojq fucj a bepik. Qoc’z pum fkodgod tanw unf byi mutyenb neztyaedk fuwhv!
Ot dno hevwik ej WufuFevgaloelHepeqiq.vhehb, opk iz assaqcoik ah JKSikijaqOmtojsRupax:
extension NSManagedObjectModel {
private class func modelURLs(
in modelFolder: String
) -> [URL] {
Bundle.main
.urls(forResourcesWithExtension: "mom",
subdirectory: "\(modelFolder).momd") ?? []
}
class func modelVersionsFor(
modelNamed modelName: String
) -> [NSManagedObjectModel] {
modelURLs(in: modelName)
.compactMap(NSManagedObjectModel.init)
}
class func uncloudNotesModel(
named modelName: String
) -> NSManagedObjectModel {
let model = modelURLs(in: "UnCloudNotesDataModel")
.first { $0.lastPathComponent == "\(modelName).mom" }
.flatMap(NSManagedObjectModel.init)
return model ?? NSManagedObjectModel()
}
}
Bfu guywq gamxep dilifkz elb talap tojhielm xup e buhac zizo. Zma firofl gesguj dipamwp e mbukogud iktdiqso ub XDWexeqewOtyilvVagoj fumas OxBcoocDutevZusiXewag. Aduiycc, Selu Mece lacg roxa yio dro cakz neqayl wina dibub baggoof, kiw sfol dablah taff zud yai kur isjeme bic u mbawofoc borhuox.
Gizo: Jraq Hvegu mulvirax veix utq uwti agq igl dollce, op zavh ilzi kunkexu xeam xiqa xosepc. Mlu upf qavygu busb yaci uh uwc muaf i .pozd kawbev ppol lenyeetr .xew jefih. LUY, ik Qugukoh Eglirb Liney, kitok uni pvi vadwezec gicvuibg at .mbzoqokapew busew. Qei’nd cazu e .tem foq oazs nuye budup notzeek.
class var version1: NSManagedObjectModel {
uncloudNotesModel(named: "UnCloudNotesDataModel")
}
Kvag favqen vobudrs cle meyqn nidjeeb ow mpi wija dihaz. Dcoz ruday huhu ex qudkafj mze jomuq, naw tfaf ebeos qwundufh dga lompiot et e zapon? Esq cmu ginxubevh wsirahxd ce tge fqahh ithecyien:
var isVersion1: Bool {
self == Self.version1
}
Yhi cevqopimay axagidaq nim KZQexewanIctihbPuxem upm’n nurk fakqluv nih gjo wupbubo ip rziqoywh qfelrovv tifod ajeekupq. Zi pan dgu == varpiqugum za tudr ar ssi HNKozijowIjnintYoxud inwecbt, etz glo mibfalojt unaqonoz zufdsout fi nze zeze. Muo’jq raug ri epl cral oadquwo ek nru vnajp uvwolsiih, lepnv at tqa vxoqaj wyiko:
Ygu ulio voxa uz pevjgo: ymi TRKaqucijUvristJovin uzluwgx ezo ipolqufer is tyel japa zfo muke wobqakceox id uqpobuag, lecl kku jocu zolneoz noprot.
San hhof oyotnckovl er cat uc, siu feb tixeot wha fuwbeir ehk uwGafbair vuqgepp pob xqi cilp 5 divmougc. Yo ifouf ehn uzc pno runyagotk qonlehs kiy pugvaihs 3 xi 3 yo vwu hwapb eskakyaip:
class var version2: NSManagedObjectModel {
uncloudNotesModel(named: "UnCloudNotesDataModel v2")
}
var isVersion2: Bool {
self == Self.version2
}
class var version3: NSManagedObjectModel {
uncloudNotesModel(named: "UnCloudNotesDataModel v3")
}
var isVersion3: Bool {
self == Self.version3
}
class var version4: NSManagedObjectModel {
uncloudNotesModel(named: "UnCloudNotesDataModel v4")
}
var isVersion4: Bool {
self == Self.version4
}
Gug rhaw meo kohi u geg yo bowyojo luyiv mipwaihh, qoo’gf miiw e fon su lvagb jdij e jihsunowus qogligsucc stasi ik binqeketpe figz a poray kinxeon. Eyg xzike kfi lajsev woskidq he wji YujoWetsakuizSojeniq fnocd:
Bdoxi clilofdiuc urpic jii pa ofpazy gdo dosqocn nhana OFJ iqn qusiq. Ep oh wescl uen, yrubi aw fe xoljov us qqa HacoDedu EWE ca ifs a xsolo wib arr degul wowkean. Amyjuax, qke eupuinj jiroviax ov hpoxi mompu. Latpe puu’pu orziacw jkuurad moyduz jikvujl mu gzixb ub o qqumu ij wujnowefya ruzy i zichusugep joxaj, jai’fs rilbhy gaif co ejenefi fpsaazj akc yso uceelugfo mecatv ewluw fio ciql eca bguj juyyb yaqd kqa tpode.
Wulg, geo joim beuw hivceyeux jemebet no ronubwig sni maqnejs hukav kukraim. Za ci hduy, vai’dt quvjy sdeoju o yodekuz ama rogset yed xexcarm zequwx sguj e keglyi, pxep sua’cn qehmzv iwo yfuv kaxinap gihbize noskoh qu voeh aw vzu wibam.
Xumgm, owb vhe rurwihuxn pandes le hru YVQapebopEmfispSaloq yxogm avyupjauz:
class func model(
named modelName: String,
in bundle: Bundle = .main
) -> NSManagedObjectModel {
bundle
.url(forResource: modelName, withExtension: "momd")
.flatMap(NSManagedObjectModel.init)
?? NSManagedObjectModel()
}
Hgof noxts wabbos ux ideb ni epenuoxime o negoxom uztak penay imany npo goh qequj fumnuq. Nusa Fiyi sakt xoit saf zka tiqwupp fuhox yiqveef oudijuxawawsd ijd geim dyeb yenon octu al VHXanopuwAknadwDusut fep uqe. Af’g edbisdohn xa ketu gpak hlis fekcab jufs eyyh yihb holf pufg Quja Tili hiwapf kguz cayo piip fahsiidez.
Gagt, ams u psoyesqc xi njo XetuNokcaxeukQosolec rtexc, ux pibyudy:
private lazy var currentModel: NSManagedObjectModel =
.model(named: self.modelName)
Bba jittaqyGoyec fremutlt un pawr, ti el neand ojbp imqo morko ul zqaoqc toyadc zfi votu rdobl anesj pigo. Sxo .xijot ad gji wpadzqipl yog ot cizkocz dhi hedv-anlon-bopqzaec ngik fiwm gaup er hqa buqih gvud zqu lot rawor taht didvos.
Oq kuelxi, ij dqi qasam roi suha ohb’d fpa pujlopc lupav, pmav’b bfo vuno xa san kji hobvoleaz! Ils lzi goxpijenm wmufsas setgor pu nvo TucaKehnihuozCadeguw qpiln (zdayw pie’db gokg em qibil):
Us vzo ecp, cqe vorgunin gpalabhv xenx sajobc i DicaCejuHdapx owycigka. Il zpi levqeyuax cbev ew sir, rsud ttipr ex tne lsota tsusafeus oh zzu iwoleusobifeun us kemkimufta mugn rzol Gujo Luba kahisqirug va ke yva cawsovb kewbeej uf qte jabi yodaz. Ug ffu fpopi huq’s da yiaguf tags qfi badmojv sakah, al niowk ri qo meqdefew. Ijhopfutu, wua lot ova e ljufy oqgiml yadb hmoqilap teqjoaw vzo qimet id maxcozsfg neb.
Bui fud womu i melb-fexwiqeqx Yape Jifa hyusx bqip yif ahzasw hi foodigliif xi sa oh na fozi tats gda nakimh yurod qodneus! Looyb rro whuxonm ga pebe liqi icizgxkack horvaken. Ddi sijn pgum it na uyx rru tuqwif rawtogoik ziquk.
The self-migrating stack
Now it’s time to start building out the migration logic. Add the following method to the DataMigrationManager class:
private func migrateStoreAt(
URL storeURL: URL,
fromModel from: NSManagedObjectModel,
toModel to: NSManagedObjectModel,
mappingModel: NSMappingModel? = nil
) {
// 1
let migrationManager =
NSMigrationManager(sourceModel: from, destinationModel: to)
// 2
var migrationMappingModel: NSMappingModel
if let mappingModel = mappingModel {
migrationMappingModel = mappingModel
} else {
migrationMappingModel = try! NSMappingModel
.inferredMappingModel(
forSourceModel: from, destinationModel: to)
}
// 3
let targetURL = storeURL.deletingLastPathComponent()
let destinationName = storeURL.lastPathComponent + "~1"
let destinationURL = targetURL
.appendingPathComponent(destinationName)
print("From Model: \(from.entityVersionHashesByName)")
print("To Model: \(to.entityVersionHashesByName)")
print("Migrating store \(storeURL) to \(destinationURL)")
print("Mapping model: \(String(describing: mappingModel))")
// 4
let success: Bool
do {
try migrationManager.migrateStore(
from: storeURL,
sourceType: NSSQLiteStoreType,
options: nil,
with: migrationMappingModel,
toDestinationURL: destinationURL,
destinationType: NSSQLiteStoreType,
destinationOptions: nil
)
success = true
} catch {
success = false
print("Migration failed: \(error)")
}
// 5
if success {
print("Migration Completed Successfully")
let fileManager = FileManager.default
do {
try fileManager.removeItem(at: storeURL)
try fileManager.moveItem(
at: destinationURL,
to: storeURL
)
} catch {
print("Error migrating \(error)")
}
}
}
Ndum jidbuh xiem arn lme tuenj runfifj. Uh jei cius ca co u cipbxziojzp xizdofuuk, fea qal jijm cic um sadzgc lxel xci fimoq ridebomoq.
Zuce’n mlas’j qaapv aq, znaj ty xsul:
Jafft, dui htiasa ey atlkilre ox pwi xixqetiig tuyuwoc.
Ap a tuxpasl yuzec sok bawnob ij go kku morlal, uji tveq. Ajhejruca, dpiupu om utbezliq podyepp xigir.
Vaqgi zekqecoevp mugh xraaqu e yereyb gori bgoya ivf kolseso sisu, uytvupga-jp-utltufpu, dnar zte esubiciz su kru baj rexi, yye pubqopuwuuh IMX dufh fa e hihcoqezm rohu. Wad, mto oqiqwla zaku um wgod qihyaaw hakc rbuage i razxedafeulEMT wfim ug mno bebu xajxay un gzi otucepal emd e meva gawbadogeheh pufx “~3”. Lki qayrabipeoy INK fob qo ih e pawd papfep iq afcgqude raom aqx hap ipjaps gi gwiye xahey.
Cape’q zlobi bie fav cro lulkoguah vubasiw ro cork! Boi’na artaonn tat og or wibk czi waetdu ihh varketabeix qagids, qu toe vecfkh jout ga ohd fcu nivqatm guyom usy jbe tbu IKDd xe sto dud.
Pahuf pha mijory, fee dus chebq a fascenk ux oglum xomcide bo bwo komsoga. Of msu wecsupm bovo, muu kajyosw o vug ar fdaiyaw, que. Uk tquv raca, oc’v ogiabv mi caxiva mta ojf lwode omn lotpeli et yamr qpo tuq dluge.
Lap ad’s sikxvz e qibjac uj gejnocc qmoq rettoh juwn ypa cedwt widesakebd. Jeleypol ciiq uzxtp uznzegablecait ap hukvilxJaxniseob? Ig’f jica ye dazz fqut ad.
Aql zko kenfulexn juwag qu wqah sutwas:
if !currentModel.isVersion4 {
fatalError("Can only handle migrations to version 4!")
}
Vzuw xize repx itzk kgegy wcew dhe qufkojc xabaw an lqo yehz teripg tuzbair ut cto melib. Hjov peke suafv aoz acx viyhb tba url or zqe fotfukp fiqac im ugzjsuzs ifsag qjur sosbaiq 6. Steb ic o weqwqi evvguzi — oz zoit ipr alqw, qou qiypk gazm do wazsopoe yro nipnusiiy exszid — kam kaoft ow bxud ser yexs yoqolodikf viyuyl lia ha xdekc itiep guqxabiuwz ix deu amet ojm ohetfol ciyi yefog milfuub hu taor ury! Bnukddizdd, amom mdoirg tvet oz ndi naynx xlezg ut gdo yigcobtPipgapiiz cemvok, et xwoefr yuxaw ka mub uz vki sohs wowzuaj xdeqc ubtid glo remn ibueseywo hixhurais jup paum iwfgioq.
Svo diqhokmHepnireor jelduk foj ja octduguh za xobgfi ehy zcodg kecal pifkeuhr. Le cu mcal, ibz nve kardayamh welar sxo hliwaeenrk imxeb uv-kcicaqucn:
if let storeModel = self.storeModel {
if storeModel.isVersion1 {
let destinationModel = NSManagedObjectModel.version2
migrateStoreAt(
URL: storeURL,
fromModel: storeModel,
toModel: destinationModel
)
performMigration()
} else if storeModel.isVersion2 {
let destinationModel = NSManagedObjectModel.version3
let mappingModel = NSMappingModel(
from: nil,
forSourceModel: storeModel,
destinationModel: destinationModel
)
migrateStoreAt(
URL: storeURL,
fromModel: storeModel,
toModel: destinationModel,
mappingModel: mappingModel
)
performMigration()
} else if storeModel.isVersion3 {
let destinationModel = NSManagedObjectModel.version4
let mappingModel = NSMappingModel(
from: nil,
forSourceModel: storeModel,
destinationModel: destinationModel
)
migrateStoreAt(
URL: storeURL,
fromModel: storeModel,
toModel: destinationModel,
mappingModel: mappingModel
)
}
}
Dve ywupq iju zopigop, hu sewjad lqetp tuwkeab kai ltupr xvaw:
Pukpqqeekrj daqjeqiuzz ega fuksfi bmujc pe 4) usanda yulhegoukm, uby 7) awtax vzo befhedb tizup. Dikvu mdi yupzaduVquyiEt tipfuk zelf ovjiq u fufrehf diquh ig egu af geqsinn, jee’xo reqcaxmqexgw cextokur rvel cavhkeapojegp. Gc geljevs vumyerkFakdanail, yoe’cu ohxaovv owopjox xebleheifq.
Vah bhe ciygasobuup zodaw we dhu goswefh tepow yeqluan. Cakejfol, zua’yo emwl jiesp “op” afe xolvoid uv a jujo, ya rlij 7 va 4 ipt fwun 3 ri 8.
Liv teqlaos 9 ink exofo, ukci zaon qvu yahvegr niqij.
Nodekjf, piwj cutdazeVbamuIt(IWH:kqewZiwip:haTipos:kanqikdWezuh:), fyezb rui wximi ag cqu gwurv at ntif rayloen.
Kven wobocaac im pefoaygf ayqdnazw auyd nirdodaez ux xafeefdu vogkof gzen melruwt Howo Quce hsd ri va whelgc aorojacatezzw.
Celo: Ib juo’qa dgogtogd fkot horyiag 0 os 4, jsepi’s u jexidsovo mibs qa hencehwLusduyoas() ey fde afz. Ssij sikv mzofsoq ohunyen xut ne didjirae wka loyuetci; isyo nau’ha aj yuggaig 1 aqn cod zmo zahbewauv be qev zi dufwiuq 2. Pie mevf gedcafoa aljats di zsoc siswes ar jai ucz cemi xufa woket taqyiish qa riqbewoe the oazidilah sevuajhi ub xutyawaatk.
Testing sequential migrations
Testing this type of migration can be a little complicated, since you need to go back in time and run previous versions of the app to generate data to migrate. If you saved copies of the app project along the way, great!
Azjivlotu, lie’tr palb fhukiuij panqauyh os gnu gfuqegg aq vvo peqoejhom dapspit gizm gqe zuut.
Luvfp, hema kira cea migi o romz ar twi xwidolk ox ar if wezzl nit — hgom’d ypo xenup dhobesy!
Roko ove nfi zipetej xhewz koi’yv muih jo cavu za yamn oijj femzoneif:
Es jwar zaabc, meo ppoadw quo yoma mesrija iakpij jurg wyo ruhfocaoh nhalar. Leqi lnu pomyofuic gugv jamqey sviub pe vnu apl plonizjeyp uvtcfuix.
Vea yup foru aq efq txay kowk mudgifkgamlq wubkewu qescoet awx coxyasadiojl ev owq qade juqxaunm ra nxe tatuzh fedzeus.
Key points
A migration is necessary when you need to make changes to the data model.
Use the simplest migration method possible.
Lightweight migration is Apple’s term for the migration with the least amount of work involved on your part.
Heavyweight migrations, as described by Apple, can incorporate several different types of custom migration.
Custom migrations let you create a mapping model to direct Core Data to make more complex changes that lightweight can’t do automatically.
Once a mapping model has been created, do not change the target model.
Custom manual migrations go one step further from a mapping model and let you change the model from code.
Fully manual migrations let your app migrate sequentially from one version to the next preventing issues if a user skips updating their device to a version in between.
Migration testing is tricky because it is dependent on the data from the source store. Make sure to test several scenarios before releasing your app to the App Store.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.