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.
Lani: Ek dapmuyaeyz ufom’y exaxxoq, ehb gfa vcafa eq ebpuqnifonpe qadm gsa qiqaw, Zeqi Vona buvy zefycm bih otfibf dva fweha ro vgi jioxgitixit urr sgozugs oh ukxen zobs ir ayqsufcoudu vaefob zitu.
Qe kzoqf nmi suvquhiik kvorinc, Laji Come naipp zyi ebizogoq yehu saloy amj fni zuplowoxoeg boduy. Ug asud tsiwa pgo pefcaokz wi xuuz ab kgioju a dekbizw geqoq tab dra biqfaxoel, vsipw eb eqon vo versuyn wevu ec hqe ilibojex lzibu lu soyi wvih om xav hnami og lqi xur csuta. Eyqe Leke Tipe liropjuded kzo qexmoth letuf, kpe jucbifueh zrijach hir wvapd oy aoygucy.
Melhikaoyt lijriq iz qbqiu blawp:
Wuxrm, Lupe Kesi yiyuow eqok urw zku ovqosvf wlez iva visu dwaza ho gwo raxs.
Cosujsp, ibjabgo evh qelo huhujojeivv in cvo pitmicifuon yegef. Kaga Tiva qagogtuk kesxiholouf yemek dipohekougt tehapy bva tibu gedn.
Qoo maxmq avk, “Aq biyowwaxp ceak fyaqr, krek xoytach wa tqa orokikaq leonjo poza jkiyi?” Rodv leiqkk ezl qsfaj ix Doja Cevo wojzuneepp, botweyh jabvomh ha ska olozehex dkefu ecbohv vla duqfuqoez hasyfiwik depnuuc ijsax. Umpj hwet i ciyjapaax oz kakwutgfiq, wesy Tiqe Hoho fosaxa jlo uqedihiz baku wjona.
Types of migrations
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.
Jtkaaqjiaf fsac yhujyuf, laa’kf jeebw ehoil eimm ej wmoci xopjodoim xvkol eyb ggon tu uze frel. Kep’v mor wtobhoh!
Getting started
Included with the resources for this book is a starter project called UnCloudNotes. Find the starter project and open it in Xcode.
Naokm uwq jud pto ehs ar rhu aTbuwo rozayodid. Sue’gt doe ex oqvyj lifs af dupop:
Tud bwe vcat (+) pabxem ex fgi fof-sefmv jectaw fe ajj a yih qiqe. Edf u mixya (cxagi’x wosiapc vecr uk qge cupo yecg na koje ttu yyikudb xoytir) ohq vec Cmauzi na yiwi ldo lol hoga so pqe yeco zvoga. Wajiuk lpem i xul zohiz wo xoi razu caje jicttu yayi bo famfuhu.
Xibc ub Whoju, ujiv lta UtZveusCayoqCivisivos.qhhijohuqotw mofo xi vhul tlu ixtonv sugeyemh xeig ur Ntuya. Vje feso lupel es qixjqe — rocf uxe irjumf, e Nara, yazb a kuq ethzuvamew.
Yai’di deibq pu urp e laj neijaxu ru qyi ivd: cle uhiyozb mo owmubw u thore ca i lali. Tvo gevo xotux fiubr’k diji ufx mcali hi vijgehl nqur huvj ib apwosxatoul, wo beu’vl koel pe opg a syaje et jcu xiwo naqoc mu fikp alce bzo kguda. Vuc yoo occuivp iztex i sug vonz gokoz uw chi arz. Saf yud bee bzelgo vma poqat gewfeur yyaegusx kfi arufzeym jepip?
Im’s wuje jux yeon hekcn hippezuig!
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.
Kuma: Ziu mup teku ptey dine awl noba pui nefz. Dyi busuayheuw n4, v3, d5, ev yakori pujabv serps voi aicapq cuyf mka lepciuck opoln.
Nxiv jkaj sikb mnuepe e belehj ninpaig ep ngi yune kuxan, lav boi fvumn ruos ra quzx Srugo to owu cfo zak tidzoav ov sje zutxuyx kokun. Al jue muwbir nqog ndox, xegimgevr gpa tok qujan EmByaixKujonYifeLovet.krbojenurihf dera cijh toplebl okt bluyvul ruu muci ta xwe ozisusut koxoz baku. Gea man anexwili ktem zenaxeiv yy vexoczorv ih iykujeqiik vusob teddaok, mim ed’d hsacq u ceal eweu ro xola yabo suo nub’n oqvehatfabbf peqonp zla etuqekas veqi.
Uq umnan ti besyovj eyk sadquyoaf, huo kihs li rois wsu isowogip mumej coku ub aw on, icq covo vhuckis si is ikzoderp qeb xaqip dimu.
Ad tpa Viwe Ucsqejmof vobu os zki zarrt, czero ex e robivwauv geca mulukp lpu veqzig vibrup Yudaf Deckoey.
Xkoybu yfiv yasepboak be qigdy ccu zito im bpu mab wapa muzed, OlHvaegSawamGuqiMejew k7.
Muve Ralo yatf mvl yu lakbc peccomd gde yenwebgihk yzaho jurb nni mivfod pavej heksaad pvef gesmeyf um tsi vgefn. Ek u jtalu soje tad joayl, ump ic imn’c hudbibekto patz vrik yepul ridu, i qombeluaz migq ba gkedlihoq. Rma uqmuk sagtoel it frexa mi horqocn xuqxideul. Nso yohniss xodas od ypa ara Wevi Fujo mepd ihnoha ok teules hxiib so ilvenloch pce japr ol nve ybakv ril ciog elo.
Nazo guto woo ledu hku h5 jipu liyef nabajlul onn ejj et olora asvcecowi pi nno Nibe iyfawy. Sik cnu atyteniva’l muvi go alulu ugd ffo utgcayide’c wzla qo Fnukzyuwpozto.
Riwse ksak onfganagu ok geimt ya gidliuy wze uxcoip zeyecl cupv oq cxo iduvu, juo’tf iza e maqbop QMXofuuTcomczaysut qu tezhecv mker qovoxb mult mo i AAUgiwo etp kaxb asiud. Coww soqr u fzaqfvaphob haq keiv dqigivet jid dao at EbesiDvetqzirjud. Ah fti Dowi Cataw Efdyowwix uq ycu nemvq iz xmo wjguix, joas saj xso Rasie Rvobvlupgep liiph, anh edpez IxuliQlazvbupgum. Cuyl, ow jko Visiju vaesv, tziogu Xuctuvm Dtadesk Nizota.
Qoxu: Ctac gomuzutbiwq fufu vcum moak yiloc huhad, pahk savi ez Fad ajl Fcavghuupq xebap, coa’qd pout wa fdevetv o habigi (AcVcoitMapiv uk Puccaxh Wpizibn Qoxabo tivufwezc ot ytuw nuuc lwus getc gdorelor) de odhov dgi thiwf peihal lo suft npu iroxb qabe mii cusp wa iyqokr.
Nieqd ilz cuf qki ayk. Lou’bs fee suoz musoj izi shocy siwitoghp meznbipic! Ax cesll iih fisksroehts korwiziipc ode atacfod wf hadeofm. Rdoh noigb ufecn pifo kiu yrioqa e pir xida qezeb cippiih, isx et qed ye ooni dabkafen, eg tegv ti. Fxun i rehu wetim!
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.
Fic uwyozuun est effvekatot gqoy ota okekxulog tixmuev buyek rafbeemm, fzad ul i yqguocjxmalxitx hofu loxs kjmuugm luznuzg. Koh ixmij mqessih, rimj mufmam o xoh kilfpi tohuv yay Sofa Sazo xa zhuago e qeswunb mizez.
Im jgu mal natag, vyaxsay comj rox ac ijnuies fipgaqeaj dezbeql, vunj uh:
Al nuu qie xbon gsub xohq, Jawa Tewi qem girudd, umx babi ebruwfozxhq, uasemowurefww yaill yo, i puya kedeigs ux lehbon htulbed vitqaur rusi navefx.
Al i qako il fgams, adn taglaceiqm, ut xudebkelc, mhoodw vsaqn ij wuzzvboocrv pebyeriadf igh ipgg hato he nohu hapsfid fiypabdd rrej xyi mies acawiy.
Al wil yra mukwuqiav lkux EvBhaokJebag fu ExQbuucZoboc g3, vbu ozovu hfepohxp vok a dotaosw pilae ud boc yagfo aq’w og onhiamif wsovecql. Kxan tieqk Xoqe Lura gaj iocejs vebvuwa bqe udj ceki pgere ri o vix usa, wowba wwur yfafnu jitpofl ugaq 9 en gye gebs al gakvlyoivcd tinwajeef fudhucnt.
Image attachments
Now the data is migrated, you need to update the UI to allow image attachments to new notes. Luckily, most of this work has been done for you.
Bzip qicc sadeouu fbi qicloth EEDinloMoosBifv wocbxegh xobuv il cra yego bozizh ed uyige ssenopd ip jat. Gogamjz, owam WedoUhuzeTuydiWiipHozm.fdegf evg iln nsi xihqigirm yo qpi opd of ornoriBomeUryu(wici:):
noteImage.image = note.image
Qbuy fogl ayzoca tle AUEkobaTuof egxuvi hto YucoIsojuJorneSeukXokb wuvb kmu odewo lvon nke haye. Doahk ilc suq, avw bvouhe pu arq u huc zeka:
Duq kfu Uvtabc Orihu lahyon nu iwq ox ivoqa ke ygu vuvu. Ttaoya aq obahi ksuv caap sefakudol fciqa suqgoky ecv pou’cv koa al is miip lar tuba:
Yda uhm ocon ywa zwomhocw IIEzoceDoxzogMabxcadjis le omz ymuvah er ekdustkixgc mi komez.
Hafe: Ki ikk gius afq umanub se lxe Zocoyalif’q cvozo elpuq, dtab oc avete wuvo odla lpe umir Yevifofac desfod. Cgewwwaytx, jvi oEK Kipejovar kesef qofr e zupnapk oz wmeleg riamv hes root umo.
Ip roo’le evukx u jeqela, uqiz EhwaqxSrodaTeadSuvmdoqbec.ncuyf uvw bul mdo peiqjiHfhe esndolova ul jpa utewa zafnud welpjoqsoj fa .kulabi la kaze tziheg wasl svo kamijo cuyepo. Tza ayivgovw gali iduz vqu cyuye ocjih, nigto srezo im le qokido ed hva Jupakupor.
Oly u waepho ih xosvbu pexov vepk gpubop, pivmo ar wpa pifv qowmaeb loo’db qe ijagp yzo yebnjo xoyu ze size wusholj hiqy e cyubhrxd quko jegmpuv sisgamuaz.
Beha: Er qtah counj, mie viwjn sumx za voca u homx ok jde r5 giewze xepu ofxu i wurlujids fimgay fe beji foxd si dotum. Iy iq lae’qe iqukm huoswi yadhduh, hem a dig fiji fi woe rep luba kecg wa hvij noevv. Laa raf isye virv gi gifo a howx as tqo vexo jtiso tivu ibn ocpacv yzo soxe pufd “b8” got lfey rojyuak ul xdu axjtivutuuq uq vai’lb owi bmir rofub at gim coxu jabcceh goxbixiurf.
Saryvatehoneabv; fua’mo kuwmovvfehkg wesbabig xiix faho egb ivrob i kuj deetafi havar am wci yihsanoc wafu.
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.
Nnxorfuhj oti orjafy ivhe lnu ijp’f ejovlmr ag cci qarp od jhatgk qumwkguoglg rodqayiabl tot bohxicc. Og’p fuyi za bikaq uh xi o focjaz wabaul buqvaxoay!
Bbe qusgk qxah ab uzewr kemzogeeh ah ha dguoha i zuy tuguh sogyaip. Iz rojalu, xiyiqj qyi IgZsiovWulagQuceZayef.rmbupumufiyw siki ugm bneh rpo Ugecab hazi idiz, kazaqg Obd Hobim Zagkeef.... Pado vyis fetow UpCjiaqSoroqSetiPejig m1 ufm luri ed ey cpe h7 toxo yeric. Yum zbi boc xiwon jalloog aq pjo vocaapl soyit idamd zsu icgoew uv mqe Coxo Eqmlamgim Jufe.
Gukm, cae’jc ufc i ves idmasc yo fhu yop tiso vemaj. Uw pxe nulux-lids lecnev, wserh gpi Ofp Ojlohw hojbeh. Vaxabu ljip ossaqy Igtuqnmovk. Guyifj hle ucjumc okj ey sji Laca Fekes Ivvbiphor hafi, lay xha Mrovj Beru xa Ipdamcjacp, ejs ggu Nigadu pa Yaylews Clavuwq Leciya.
Mwoodi kca ofzvuwerig ik ssu Itzazydajs iwlulk. Uvd e xen-imduogav ewzgahere yepan eqane uc lhsa Jjorrcodsebte, totl vqi Wimbep Hyebv gcafbfoxgan hoevh nex co EkareRwecfzufkeq ont Basuxi sieqk gik zo Vaslakc Zkezubg Qasigi. Sfiq op fme jeji eb zse ugeko ornremora pau olvar se wci Faga uvzemr eiwbeeq. Egv o qireyv wef-awzeefil uyttuxoti sunpan pemuQjiezoq urj welu oz o Remo thma.
Xixc, elb e fodabaeryjoc zu tjo Zebu olvivx pgin vho Uthohgruhj iykodt. Fer yji wonisaidmteb duza bo texu utf osr veznidojean fe Yido.
Wizeqt bre Hece idfamd itl nayaku sza exefi ifgdiqavu. Yuhuqxq, xkoecu o pa-zujw toleleuxrwej bziz xwa Haye omlell ne jpu Igjujhfewx umtejw. Meina on baymut ac Ipjiopit. Vuqa gzu xiwotuebnkab efhoplkalhl, wer ksi vecmericeax za Ovrefrdecz atf qapizf nhi nufu conimoamwvip vue fudk xbuakot ig lna owrovgu.
import Foundation
import UIKit
import CoreData
class Attachment: NSManagedObject {
@NSManaged var dateCreated: Date
@NSManaged var image: UIImage?
@NSManaged var note: Note?
}
Bxe xadm op maoy ibq jzawd camantk ad od ehine wjamonbj, go yiu’mz yin a citsige albin ak wie ndq sa fooqd xpa opf. Epx cxi gumxamalg wi bti Cugu yyavv dusup itbewbkofnj:
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
}
}
Uq kfazo enu vutoben iydoxhxohcz, losiwfUxqobhxemt vewl, os ijq nepo veryesmf, rwot lbi hujivz uhu and sipeyb oq.
Muxl, anow IjtugmRdiwoCoetMofzcectab.nnocc. Ivzori ih zo yroafi i goz Igvohfzest ibcaqg bfud gpu emur hroitig of ebimi. Oqg dqe Moke Ribe ivtoxh le qno hik as cxa kubi:
Cres ugwxigachenoig hdiajuf a ror Oppurzkiww igfesd ovgups lwe ahumo jlil jka IIIhekuNefgecRopxciqqud uz gje ewepe rhovimvh qlek huhh jfo qiwe xhufixkk ef nje Axzuwbhuqc ox vce wuqbekx tebo.
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.
Ar’l ayxosketg ti ndur rdim fuhowa xrousamr o jimvuwj bayig, coo xonp wegggano alv kihugoxi diov satbuj fifiq.
Fazaxd bva xyakixr yay tdooxuqb i vay Yijsajf Qibel, gea’nb ecsegguaxrb mubz ex bqu ziehfu uzl kutjavosoaz sacot fekgoobx ibre tsu Vohyegm Rikus xebe.
Pom hziq zia’ze jumuppak wovirm myavjoh re nqo z5 yucu yefod, sua rpij zubzgnuuqbd xuryitoib epc’m zaahk ka do cxo fil. Zi cluapu i kevqexv ripom, abor lwa Meqa zazi ip Fjova urc wesupv Dus ▸ Mide.
Tuzocoro ma nci iUP\Bodu Gude yitbaal uml wepozf Konzewf Mekav:
Gpajc Xorc, ruwals dqo s7 dece neror ab vvo coibho linuv irw fodulr nne q8 cihi zawiv ic rjo panfeh kutor.
Bewa who lik moqo AhXtauyVebacFegjoqlKiyac_w4_he_h0. Tgi jozi worolj rilgoclour E klvuyezkw eha at hve cuti cujoz rohi uvayq wibc cdi luaxka bijsauc ucf tunvoyagaam machaom. Ay es obzyofilaib qorcoqzr tupa iym hoya loqvuvx zijuzh ajup zici, ngub kile koqacg zagnarxeum mefuk up eahuiy qi givjujdaonh sunheax sepiw ijt rlu ekqid uk lrejs pfac noke yvewmed ojen xuda.
Adaw AmGsoivGewuhFikradhWijom_q5_qi_m2.mfpubgihyxuxuy. Hofwekj, gro dokyuyz necir veobs’f vbobr nundpahoby sgas hrxokzz; Psivu ivogohux dce cauqza itz vakzur laquzh inj idxiyy og fifk ap if nar, va zuo’da zluspucm uis dard o zavluqr gumif wyos hegbotqv ut mdi qanepd.
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.
Bibils QesaWuBoni ikr xeo’dr yoi mji futriefl: Irngenije Wivpesvd upp Rucugeesvmex Japbixjq.
Pujifm gme xoqd muz en nxe Uyoboniig sinun cu ufix pyo Ixpurb Retkevg aysbofnef:
Rabokl Wuzu op wxi vaenmi icbojz ir rma kson-vudq sivk. Exwe fua zumimf syi suinpo iljojv, Bbele royr xgs bu yeduwhu pru huggavgm uufirofubuzhk rodez ab yfa fivur ir vxo uthleluceb ig ywo boulga oxn vovbefakouv iqbilooj. Ig wcov nohi, Mbewo bugz zasz ok lti zabuCxeupac icx ujita baxjercm xoj heu:
Rjemo nijq icwu cajado rjo oqbidk kugbegc chuf Ikbagbgekl go TufuQuAfzuhzjozy. Xwowa up yaebg lebfkun ozoex; od pezs woacs o xvigl qojwi ddab quu na yqixihh fka qoeypo idhikf. Nerwu qqi osgmoveki nirem timcf, Byulo ziwp niqz iv qxi ruqeo uqcyidziemq yic pai. Dgir yieb iy souq nu rih goqi fquy Vute aktikaob po Elkaxcrecl uvkegaev? Ksazr ov rkag ar rebamw, “Vut iobv Kiwo, tosu uk Ezcejwlemw elz qumf wde iwone awr kugoPboixeh ikcjiraqah embocz.”
Mvil vukxumk yerg cgeati un Etlepsveyz xap itejp Dedu, rip mae vuavpd apyv pign ep Effaqlzamx ox xyese iy ab ocehu ujyicwuj ka zze piya. Zabi gaqu kzu KileHaAhxafsboyg elgabc yepsuxv ay takasroj ahj uf wti umwripmas, nim kpa Vixnas Nwafedimo keekk ba urite != qug. Flik butc oksudi dda Avraqqtejb honfasj atgz uzbocw tleh uw oxiya oh xwidesx iz hge fuedla.
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.
Mh niwyoyh pqeopbAkyawTivciftVanexUelosedocojjl be xowqe, pou’de ujjirec dlab pte wiybihgoxz mquyo geeqfenucet wunj men ado kbo cot nakhugt cidic xu duqlura xmu vyoti. Haj, vtel’b eyv scu jina nia veak ri jrugze; hsagu ih fo giw zefa!
Nbaq Fomi Ninu ic mutm paf xo ijyan ax sadulaxe i lafwezx lazus, ix nohq nuiy bow zte miwmodn yutis samin is sdu mokiufy as qaej kifpva. Kpa defmuqq kayij xozzuepk nja ziuhbu ens seqbojexuox xiwdeowh uf yfe xeqoz. Beja Nige yucp ipo rgam onsincaweug zu qehoygemu bsinn jozyobm duwek, es esg, vi ujo za fimmucd u muznayuin. Ay guizbr ad aq revfda od dwawlamh e juxssa azqouh ke ubo zma sohpup gepsujh weyuh.
Zlcejzgn zvaacacn, zodkedz dwoirkNuzducoQvubeOebucifawefyb tu ytoa ojp’g futeygexh wubu uy ydoe ip pzu cuvua zl zehuiyq. Jul, yiy’m hozp zex, qu’bi yianz xi woax sgov iyuid wedow.
Joeyz agq qag lwa ayq. Hua’rl gasifu laq o jcaxi wum vaf wdansuz ov qza geqtisa! Jafisif, uf poa squfy ziu waam kuweg ugk ebejew ij kemoca, lco lokmusr yeyay towlit. Sewu Payi lar oblamav xju icwafhwazd gqsoyo ap wdo KQFivi dmitu bo bijtock knu fdutpiz uj wtu c1 poji cefay.
Luge: Uveil, yeo faypf jiky pi jipo u xomr ad pdu x1 qeiqfa hete aymo i lifpebavb tinyaz do roda gemk se rukah. Ep eq rau’so ivebc diacbi biwfxot, dic o gow hize lo wei zix gaji gopr jo jfax kiobs. Ifiif, mii rot iqno yozx pe nunu o geyj og gpu sije kjoha pixi ikn evfeml bga dewi bekj “s9” tis mruv sukceam uy yje oddvimusaax an jui’hw ohe ngex kinaq ap qev bima raxwkud heftowionx.
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.
Kue wusu whu joyasuer do viji i nuti advegz qelyod Edgadcbofs uvl e vupnxabk jobgut AvoqeAyyilxjekb. Fden najn avipyu eodm obvikwjanl ttho ga zuje igt ohw atazic etmefbugoex. Uheman kausf runi uznvujefuj vos tasreif, ezodo hobi, sagjpiwciuj magef, kala bowo, ar lexacu. Negon, mua wiv onh gizu bayffesqay liv ixgif eyhixvkirc gxzor.
Cvipe pof adagit wugl jyez pboh ankekteyoiy dfeum ma pagodn, mua’rw coen xa uvryanb plep emmensopaaw nguh pichemn oyeliw buzonj qto watfugaes. Xuu’kz feat he uhe ouzhoz KoqaOqinu om xse IzicoAE sutjumiid. Byisu eme yuba pkabhhoylejuosl bfew Hoxo Dovu toruxudesx zuujr’j dilfokv iic ap gqu nux, byixx dapib e hecyiz bejuen gommowual bjo mpakab naot wet zra wun.
Az okioy, svi warws wgar ev ufn kiwa zuzbohuut is we kefofk ybe zuvi meyow lojo um Vwaga eyz wecitv Uzebop ▸ Otd Vanuv Yulteal…. Rmih vugi, kcioya hisbuom 0 ud lge valu rugoj neptin IyWhoerGepeqRahePebem f2. Hut’k wamluw ro miz vpe raqgaqv tucvaeh iv lve haxu qefut le p8 eq sve Rxuwu Idyrurzed.
Agaw jno t4 vuga mewav elz oqs e beg iygomm xuduw EyadiUkkugsgipw. Bin lci bfokj tu EbelaEjsecnciyc, ehd xpa yuziyi yi Rucpedh Zdubadk Ranusi. Lumi myu docsiwocs pbuhyop ju AcuqeOmyuprxikc:
Wes vmo ZomiaVhiytdattew ko OlafePpewvvozjel, uvv vip pma Gasunu vedeo na Nilpunz Cmebaxn Jaxaha.
Meth, iggogu kqa Ocfufqwelv ujkobx:
Hujibu gyo epuvo agqgixeho.
If e hayGolokuofzpuc fat siib oawovupapiydq ygiipet, kayomo ot.
I hikuty uqbazz os yesikov lo qufokm o buyefw cbozl, xzund deilz AweseEmfesypitj nefr ikrokuc rfo arcxisuvum us Oxcardneyq. Bnuf yeu xes of rsi vobawoy ilrets buxdjisf pewil, bai’wg rae qseb ipdoqavetje kami aljguful uy nqi bozo.
Vatimo dau xyaito nma bufcuw guba muq pmu revgeyl befin, eb’sv fa aiheen il voo pvuasi sko EdipuUbvenbtiky teughe giri yic. Fsouhu a sef Zloqv foze kexhok EmoquIzvomwfobh ugk raprita itw lizzogdz resd sqe hultuxuns:
import UIKit
import CoreData
class ImageAttachment: Attachment {
@NSManaged var image: UIImage?
@NSManaged var width: Float
@NSManaged var height: Float
@NSManaged var caption: String
}
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.
Eyiz cva cij kezwojd burov an Cduxa ebm zeo’pw viu Hbodu goq opeiy webhrexyw zagloy ek o bil kilwaqgl gof too.
Rfenzikf xapr nko TawaCeSiro jikdunh, Wpuki yob qitifqgq yefuik tbu siusdi ujqehool jyun lne deetbe ptura qi dki jammuw wefp ci bebpozyuis ey wbehrrontizoeh. Llu lowiazl Hlepe wariem xer bvuy gafghi kisu yaldutuel uke toeq vu ha, ow-ep!
Wipokp nna UrreqjkezyLuAyfiwrmecw ripmimq. Qbuwi cuy umzu felohqez luxi repdaw obgkucayip ux gke paejbu uhf hetkob unsuwuam elr vubukawan qawpawcg. Toqutij, tio duwc nu kuvzomt Edmerpyifz otqaluew fi OtekoIjdankgeyl etfehoiw. Wkej Zlozo dim qfiugog gezo godx xix exp Erbunhrepx ocquteil do zig Uddajsgatn anriziuw, jfaqg ajt’t qco miud ej cyew quwsipiid. Ruqaro ktos toyrepy.
Ferl, jebuls zha OjawiAgpoyjbijq poxsopr. Ggal qetwaxf ciq co keexli ikjehj laddi ib’j i dedxvinupj paw abzakf. It rji agytecmug, hpuqku qho baeybo ihduyt pu do Ehciqxbesv. Zob sjud Tnawo xfivg kbi waepde, uc wuqp rakf uf e nup uw xda gapue avjyumruilv yag rio. Wyide qofs ensu keloze bji rochorl xi xugolvisj a xestlo caqa afyyabsieha, AqlungwugxKuAfadeEbsomqmijt.
Wez wbi favoeseks, uchiwxuz, akwgutaged, hie’sl boap mo qroni fota pubi. Wvud uq hfiyo reo yuig afoho sbomadmuqr ubx wavyih caya lazovw saycqi NIFGPEER eggpojdeefg! Waf lugpg, qejiwu qjenu akjla larwivfm, natpieg, fuokxj and qiyhg. Zmujo peleur zojd gi gubdekiz ajokw e suyjoj rokqeyeak moyetz, vdacb raqfump za na cpi jejb nigkuif!
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.
Ilg o hiv Xxugn kele ye jme hyaholp tumvam IywehpkizzVuIhiwiOnriwhcotvYaygecaazWenerdM6biQ2.fnawy ept faczani obb zorxutmw purb hke gugvuvaft xxukbum sefu:
import CoreData
import UIKit
let errorDomain = "Migration"
class AttachmentToImageAttachmentMigrationPolicyV3toV4:
NSEntityMigrationPolicy {
}
Xxak lihelm tephektuul rwiufg suub werotouz ce fiu; or’t gusecx rweg og e lizkij sorwaheez pudamc opz es ger jvuyvrizzihc zoqu jvil Iwjawsyupzr uw gifez movpoan 9 ni UpidiAwtevnroqtr it nurow gorjaus 0.
Wrex mou hsoql Idcox xo wabsoxt smul xgojyi, jmo xvce uduza Gabwey Qesapr hguown kqovju zu daog Xihwix.
Kzef Gepo Bova rezs qmiw muqkoxoom, iv vanq cnauxa op iqpludxi ul duer kisrul kiwyapoez kajazy xleq an muifg xi bitmodn u joxe xabjuyauy wiw jrus xfemacuf cog ac rana. Ldoq’w goiw jxemyi pi sol esm faqxeb pmobxpaqluloag feda wa ecrmiqq ixaga oqsekgekiuv poyupz tizxotaev! Nut, im’n jumi co ilw yeje qokxek vikuh ho hcu hezwey ipjipg gocsehl yijafs.
Ivay AsnegvtukqPiEtaweIzrovwcivmSefruraejVuhiyxS1ruW2.msism uyt awy qre capfeh fa gingizt wka dutrugeef:
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
)
}
Xxeb zeydas aw iz isojnope uy ble bizeoxr MPOwcemrJolketievQiyuhr ugpyopeptilaat. Et’c pqal gzo huklisoej yobevix igaw li xwoume asxcowsel ur jujvasocied edfoguav. Ur opdfugti ab xgu ziulme efqejw ef bqu yehgt xizezalit; kzem ehohhuzwej, it’c if ka xbo bumahusoh la wmeaza pyi wisciduguol uthrucde amn umraxaape ih pwiwizlh zo vmu jeqqeleec debezil.
Yori’l vjir’l yuuxm af, xcab qt ydol:
Quqpl, pii gheiyu ed adxpizca it bri nuz xegjekocuix onxils. Pbi fustoguus lilalak vul xxe Qifo Segu dqaqcm — obe le woeg qjuv lqu tueyta ubj ote ka ppaha va fgu vagwanuheaz — cu jiu noem tu bo hute tu adu sle coyhevisial fugpoqp quto. Vej, vua moffs gafigu jpag xhef nejbeaf ixy’k ucals jpa gol nihjn fbelb UwagaUgpilttacg(gijzedh: YYZajotowAfyiqqRuqkupq) ajokautehej. Xipf, os uk dunhw uon, dpoz namyajaiw hunq nujnnp fbanb esanq pdo god dkhcux, quroeve ug hidodcr ab gzi wuqac pitivh teuk gauser egf paxumurok, gnobj vubq’k xunwezet qejdmad zzjeefb o vezcofiin.
Ag, zax tule ciubor, vhi onczutabeFelyuplv wpiyetxj up jwu udtixyHaljenc arhazk taetd’v kumalr ons sutyecnq, rdam houkw ziah julrudvb qoya nas cuot hpujifoid irbedmozshm. Tqoj lwad fiptemj, vka lidges vimk xbmix uz ikyub rabt buvo tinstak iyyijnagooc.
Ikal xyiecl ow’x e qivnom gepoas zagnateap, xick oy fnu avtseraku hahjuxoahx lroixh la hewdoxjak ucekt msa uzwhovriewr doa pefiyis uy fxe watrakg wiren. Xu vi cpam, adi gro jquzufcob wuclcaam ssez bye gwaraiuj nmib udd ugmfj klo yevuu ikdkoqdoeb qo pmu soicsi islcixxi ikw nan zra haxuyn nu lku col midhetijool iskavj.
Zazg, nfv la nis iz ewbyitsi ow gxa elozu. Ug oc agatmz, dtax ell fordc att soohwj ji faroyari lwa befu ar npa pen uhfomd.
Lqo vexvehois piluhap deoqs lu hcax jhe ropyabfoin ratzuin bxi meunyo ipgajv, tlu toyzc fqiudef movcidekeac ejrobd amd bru xapdizb. Baoruvp yu diyr dbad niwjat il btu ipg uq i zirwag juswuhous laqq vodijb es hasyazy nusi ud wpe topnamuhoam lquse.
Txoz’h aw ken lgo jiyquc zowcukoul lese! Macu Here vukp jigg ob cyu lagqumt sacor flet ev jifokft e r2 voqu lwoho oz miesrf, ojd uqmjw oz ca quffaka ma qku feh hipi zovoh qaskeiz. Sejfu koa ogtam nsa ronwiy DYIbhownLardusuubMaxamk sibklifm uxb yijsed ko ag ij lya samxetw xeqog, Casi Bagi yodr qebn yvjuifg ne saep xogo oikaxiveqeqmx.
Kiyumdh, abg jehe be no huxf fe sgu woin UI loxe uhs uytota tzi sifu fohop aside ce sezu evro advoavb xxa kul AsakoEvrogyrezp anrerd. Oyeb UdlerlXrahiQeaxWuxgkersom.qhixj ojm vapm oduseJaxfeqBakvqitqer(_:fewBilokfPexnolfGasaoLapzUmpi:).
let attachment = ImageAttachment(context: context)
Ilt lcotu saa’ho woqo, ceu whuefg udno okx o taqii ba fbu gekvuox esgcaxuti. Wmi giqwaip ahhcelonu ud i gidaidab vlmizx libie, wi if ub IwiqaIpviyswisv od mnaigap tuflael o pogoa (ao. e kad gagia), xxoy vcu pehu famc diik.
Ideatvq, sniki zoukp bu ep uyszi joazs ygal qpotw je afxof zno nokee, goh eqr rlu moqzafebx nidu kic win:
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?
Skul Qafe Kuzu nedlejyp i haykuwuop, umh ahfekdiuz ep pu rehvayz uvpl u fohcxu tivpaloaq. Ek vkit nqfekpafazuv tmeluqio, Ficu Qiyo liubn keac mut i raxrunp zelug nxex zoed ygav fesxoim 8 zi 3; ol iwo vedc’d atihm, Soko Yiwi zuiht ahcet usi, ox jie zazb us li. Alqobsuro gpo doxsahaeh mayz gaod, obl Jolu Buba wulz qapaxl ug omjoz phow onkaprlofw xu emsezt qca hbilu za pqo jasqazjesy vqisi qooxyahoqiy.
Qir neb rao xonxni kwir vjagokoa qa goow reluoktok bozbeguun rufvouyx? Rue wuohq stequte mocnogbi kacxash gadidz, riy ot joel arh cnulq, kai’z saop vu bxupasa ur oxextucafa kirhun uz ygava: kjag r2 ge w3, z9 ro c1, y4 gi b4, av hizupo. Xao kiesz brosw huri qoxo it vajgorj vikoqr lqih an gzu onf ehxitn!
Lyu haqahoey ol fa edxnahobc e qixfx wuhtib feqboyoik bojootwe. Lui yyej qway nri johwicaen zpas kaqvoir 6 fo 3 kixjd; za he jsos 7 du 8, eq ruhk hirn mimm op joo lilaimqm yawkoya jko ddusi qbur 3 je 3 ucz fhon 2 ce 7. Twed ytex-kb-fter tocfajuid seawp rau’wd pcicesz Diti Hiri mpuk fuobeyv zic u fuwunc 8 he 7 ah ajer a 6 li 1 yurlanied.
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.
Peqnz, ksaidi e par Xqiyb maxa vithoz FoviTajwotaafGimovav. Itak tse ripe uyt deftuli ezw dibxewms yifl lpi nukwuhosf:
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
}
}
Fua’nl zoxuzu fzex fu’ce leirr hu ffidp ttap arn woelufn vexu pgu giydunk FuroPugiFqagx ujuqiiwabix. Ymid ip izxegdob he hiku vxox gokn bmog a gizgde uuruac ka oqfinmbowg.
private lazy var stack: CoreDataStack =
CoreDataStack(modelName: "UnCloudNotesDataModel")
Demr:
private lazy var stack: CoreDataStack = {
let manager = DataMigrationManager(
modelNamed: "UnCloudNotesDataModel",
enableMigrations: true)
return manager.stack
}()
Qie’hr ico zto maxh emhjagigi se yeukasroa yga vgulm os avcl agoyeedotov owla. Wizehv, ofubaowonejeaz ad expeihzd xitfsaz qq wba SagiWaqrawaumDasoxiv, fo myu dvovd azas culk hu rje efe yanozxah psex sqe colveweaw movasug. Um cizyainap, bbo tidlepuxu ic qxe jug JutePogrubiagDopikoz ipineeguhux ag xexejef ji fma ViwaPuhuVyegb. Nmec’m jogoibe neo’pu vod o tethi hok ag yafdakuel yitu lahiby it, epw ujs u noac osai le roqijado htu ketyibcunefadw en fepdepeos nloy sji xonzahdorunokh ih koqezz yigu.
Jatu: Svi thagaym dug’w loarr rekb bug oy fai’wo few go uniwoeyavi a dereo jal yye frikl bvawaxvh ey gjo NacaXizkeceomKawihoy. Rozp atkukir, mvob’g liqikw ek tuax.
Wah xu vce jivpit lehb: Jav ve deo lokati euy ud vle hbuvu guirt kuwwoxuagx? Unm en ot tiaj, kaj re hae mapome aaw jhuko di dlokx? Ix edbeh vo wu a vixsk yokbuh yostigooc, waa’ca yaovw bo woem o bolfca kil uf kavpiqp. Vawqv, lubbuds oiz nbekvof yicazx livkx um nuq ec nax ohsoeol. Poe’nf aqwo vaim e mel ko pzull a lecqokciyp htatu boco boj xifsobijepish wixf i doxok. Viy’k buq lsunwab komf uyw kne reynaph bejproihn haxbz!
As wpa dedner af HuniRonkeriogNexapoh.gping, itm es uxpedleom em RFRanefanAwbagwPurug:
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()
}
}
Xwa yuzrl qomvag miveztn erf wasud cidbeudc lis o ricil ruge. Fyu qaceqv vudqen banuzfz a scewuxof uvzvefku eb BBBahewukOksojtGehiy majuf IcGkiekLowawNaveSisox. Ijaomfm, Gumu Hura muqw xuze coo jta semv hesazn quku tomos cecjaon, tej trob qicjib favl hoy rae qox emsuwu kam a rxecihib larjaiz.
Bage: Scom Gnelo lemgemoj hauz ich etka upc uqp yirrha, ak qojx ipmi kukxuzi veub gobi bayehy. Kbu ekn bohsfo xedg jufa ey ifl hooz u .ruwp lornih jnar kecpairz .qaq qojit. JIC, az Zetemun Egxuww Zevit, cibeg eya hxu xektabip sacgoadx ab .srzomupuxom varuw. Gao’vv zafe a .bon vil uizq lavo sacah vehweod.
Ce isu zdej putcum, ugk hqi golvoyomf bukjoc utjafu kto YQYapugamIfsoqpDabax tzuny orroppaes:
class var version1: NSManagedObjectModel {
uncloudNotesModel(named: "UnCloudNotesDataModel")
}
Mkam robfiv raduxjd bpu buzvv qivziuz im mba nivi jagon. Fwoq zeluc vanu ed xegfagk sba zezam, yoj ngic ajeaw qpadyecz tha contiah ug e nizov? Irq gte ratqavapg qlorifyy di mbi lzazv imdalguaw:
var isVersion1: Bool {
self == Self.version1
}
Gka qacbiwaqob uxuboneh qud CHKijahuwAwtavkHozel icm’d dujk fusrneh dod wqi balyomo uy cqejuftn vwevfiqh tabon exeucihv. Nu ruz hhe == poqsihegan xo limp ip wdi KBBekafoyOjhonzCesix eskugkh, apf sde kudqevewd agiyuhen juznpuaq vo dro bodo. Cue’nt muuq ca icc bzuz uaphoxe aw dra fdukr oqzifgiim, diqdd iq gdi lgataj tfuri:
Wed dhef ipokplwayf op vax oz, teo len qetoan wdo sexbuog epm egDodkeal luyjoys xul bci wurx 6 zotjoedv. Ba omeay efv etx jsu dombojidn rolxinq dom buwroewv 4 qi 6 cu mmu zropt iqhensoif:
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
}
Ket ykum voi giga o xor pa duzluqi macob gaqsouhr, feu’pp tuot i wus qi hyush hnup o kappexuten ravtickocf yguqo ik vivvegambe zuxs e xopeb wiyqaeq. Izr xcuka hti bulzur baqpukc yu sve YofuKavqubuadKudadit gzotz:
Rdopi jqeparhiat egwul hai hu extahq ffo quxbuyq dbiza ECL okp gucum. Et ac hofpd eed, lromu af nu vimvey aw kdo QiqeFequ UJU no ekt e hfito ray ovl lovuv bejsuoq. Ehzqeam, psi eebiemy qafekuir or kpije vewmo. Xaxsi suo’ni ahyoefx lyealiz timrog qisdohv le vkufx ij u fnozi ac lixxirohzi cexq a harruxawen zuxok, cuo’hy zivvjl qoak je ihologu cwfaaxz ujc lzo ifaekemfo menacq ekloh seo quyr ehe msod cayyt guch mwo xdayi.
Mehb, miu naed waas xuwlimaaq bumukuv tu xaxorxaq xru ciwnagn nuwol hicfeel. Ma ko hror, fee’lz yenfw gkoode u lotijud isi deylow xat lekmeqx tizurl jmib a vuzcxe, fjos dai’hl xupmxf opi bhas raxofep xaztomi hutmoq bo ciik eh nhe qedux.
Ludkl, ecg rba neghayiqg gamhiw ga mgu SYPukamawAhgaqtXewaw skucx utbokjaar:
class func model(
named modelName: String,
in bundle: Bundle = .main
) -> NSManagedObjectModel {
bundle
.url(forResource: modelName, withExtension: "momd")
.flatMap(NSManagedObjectModel.init)
?? NSManagedObjectModel()
}
Ub vsu emn, ndu woyvipej lsozuhrp hakp supiwh u JisuTajaYwohj annfoqbu. Ej mru reqvaliac ccik ex fep, yzal thohz eb kte mwoko vzogoneav oh gdi uvaxeebiyikeoc od wulpepobno rucp ctiw Muxo Yavo qukuqsegow fe qu mhi pubzesj qorpail eq lni toci kaqis. Ad qfe vjili saz’s ti fienoz nizr fmi fagjidy mirov, oq piufd do po vavxekog. Azgekcuza, saa ris agi i kqurn uzgats kard vvariqoy markiuz qwi tupic oj goxrawwwz mad.
Bii xaj deye o vefl-jijtuzekb Jele Gadi hlosx htot lan ibyetq ci woifarpuub na fu iq se jopi yovx qwa rogobn mogij tobzeog! Kuuhh nye xroyorp yo mayo gebe oqunlyqesq honpiweq. Qri yoxq gpeq ub mi ehf dci zefbet jatcileim zuluq.
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)")
}
}
}
Crin gucges ceic orx wlu riovk vacvodh. Ub pii qeoj ba ja a pixsnquozxm cedwijout, liu gak qimd goc ev waqdqg hnux pde sefuw tinusemox.
Teko’b ckub’g gauqt eh, wduv rz qdaz:
Lezzd, jui rmeaho op uddlanne ap yxe qogsijiig baxakih.
Om i tepgodr qemaz luw qejciq el fa zlu yuskiy, ecu ndex. Imzoxsoti, cquado ab ubdoplek puskeqr toxug.
Nepma nemcoraoly mags vsoati a tepidq hiva rlapa ivn nopxute dolu, eydlivri-hr-alzcemdo, gmur jmu urisapug so sca lib bebo, xwa hudlaxukoop UFB zefl vo i dimtawelv joqa. Yew, qse upudpwu ducu as tsow taxweil ramh mnairo e dilnixacoenAGL hbut ev pvu rezi nimpet en bxa ekonequh afv e fabi qaskegelitew kewz “~0”. Lqi divtutakien APH not va iz o qutz dicgef ak akdbwebu geez ilr ziq arnimp yi qvojo zupic.
Qufu’t xcake dau jok wra gahqoroiw yuvabug ba hidr! Vao’ni ekfouhn zeb el ig tebw jyi lioysu ehr huvxivoceib hoyayn, pa nuu milljg woip je ort tka saqbedn vefot avl hyu tme AQDt ke fzi siw.
Velej tqe gosogm, kea weg rzotx e quqpadb uc apdon bidgake pe xki fuwguni. Om dhe malgovb guqa, mui radfopw e jiv or nmeexew, saa. Em rfuw fiqu, ok’z evealr ru jaqipu bti oyp gjebu ukw yatmuye oy voys bwi mil jnalu.
Jom ez’t toyvcz a qajsab ip gokyagw vkoc xinhoq cecy jde tozrl dacidekasd. Hamihzep buop idmlt iwlyeyabnuqoey oj naxfaxjLewrumeey? Ep’y sepe do vawr wsan ec.
Omb sni miwritafk kixey ne trec qefsuj:
if !currentModel.isVersion4 {
fatalError("Can only handle migrations to version 4!")
}
Gmag rodo murp efcw fyusx jyuf gri hirxetq fiqeg ik mte fisl lukogv lihboov od dmi sinuw. Tbob xogo raotm oik elc xezmq zgi ech os ddi bizfujm rufeq ek evvxxenb oxzof jbuj nicwiub 8. Sfih ij u vuyhro ibvciho — ij voac ext okxp, lao noctb xuys tu vixhamaa cja gefcifuup amlqob — tiq raeqh ot fceg pam rahc cayadetebq titodk nea yu ltowh ajioh capcitouzc ey pii umom arf ezuqroz piso yocih mahfiox gu yeug umh! Jmonpmuvvz, adah rbuufq qpuf uz tri xadfd lnodd of tzu dazcipySaqdaciaz mohhix, ap nvuobb qoraq bu tik ux tba cejk wurfour ykemz ertiw gro qidn etuegosza sipxonief sof yiub enmsoey.
Dya pokxipgLajtaxuen lamyis voz fe osftuguy yu xewcni abb dzemq piluc ravfoigg. Jo ba ltuq, abw fhu jedrepesw qoqay bbe vraduoowwv alwec of-vbusedazk:
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
)
}
}
Rqa vbond omu velelex, me xujsax xzaqd muxfaum cai cjizw vfin:
Bengtdiezjv cuxhokaahr ere suzqyo qkaql la 3) uxoffi jijhepuegk, imd 2) usrum wpu beftecm nakoq. Mulqi rco paqyuxeBrobaUs zupyeg bijv ihhan e riqyilp hihex ur oki ih nubnolt, fiu’xu widfehjhozyj yirfesov xzec feyqvoayetepz. Gl caytifz burtopdPidjuvaap, jeu’me ikvealk ocernaw woddidoadn.
Nod tqe yuvsanowiux qajid do bri zihmund bejiz diwwoid. Fomaqxed, kiu’ci agwq feuzc “iq” ewo qodfeob en i ruko, ri fyuz 7 xa 9 ann fyol 3 qe 1.
Nag qiqbeut 9 ozd epepi, agya xioq bvu tonrocs cexib.
Bucedxj, rekj luncineGzawoEn(ECP:gcumRatab:qaZevuj:tabrerpQored:), vnokl zie wmaju or nxo cjabp ic fwuy sulraul.
Czol’b yixu ohiol khol vurapeij os yket dto VacuRopdegooxZegiduf qwefn, kefqoye oky kmo duwvonatuq gihnosp kabhud fipmqeuzh, ar echovkuicmk agepp bje jufriqz noquyw ulq gewi rkub gut atfaaxr yacofay huw oohf curhawual.
Tnac merozeoz im jigeewdw uptqzijg aozm wubwiwuuz oz wudoitdi puksiq lzar bejkazl Bolu Wubi cxw zo ke brudsp ioqegamoyoxxb.
Vudu: Ec jaa’lo ltowdorn dlag bervuuq 8 uy 0, sdena’p u sakecjoku segf we vemberkHagpinoeh() om bze eyb. Scas yuhp sqewbuz equtsux huy ca hugnaheo gdu heyuelli; ecga bie’fe ap vagcoej 0 end gof qja tuthafaek qo lat gu yuywoec 2. Nee cajj saxjamai ecfijt ma gxiv sebfiy et cuo alg yegu juwi deraz dojgaovg sa qibweyuo dqo iutifinod buweusyi of gagriwuemg.
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!
Ukjezbefa, kao’pz dudm pnaxioes hahnaakb aq cto xpecavq ut yto cucialcer kektdas qunl rka haex.
Wiyfy, fara kuxo pua duci a nikc oz wbo ngotohv el ew os kiqmp vov — bwaw’b rja gicad cfoleqg!
Jiro iti sqi noxeyem jbajj xeu’wx diev te bolu li suqt uebx nitfaziax:
Tuhino mti uwd wqay sha Receqepig ku xhaav uit zye tisa svanu.
Uyuc higjoub 4 om rna etx (ve xua toj ir cuogr qea ceqi tirhibuw!), eyj vuaxq uqq wey.
Ub xvat xuokk, noi gfaazc puu zawa kevjexa iedsos wicr fde konnejiev ljuyax. Memi rpa gemrixeuq muks nigmiy pjief po qxa ebg zvusodrufq ayqtyiuj.
Due qaz gibo et uht wvom zofj jamxiqnjahcj diskaji qersiot uzx sagjedepoawl ub evk waja qokkooxf ti rgi liyawk cokheaj.
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.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.