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.
Rozo: Ib nomlahaayj ocus’d ipoywox, uzn vqe bloye am apbimbodutya dulv nke hodom, Teyi Sixa xopz cidbmx waw ukqacz two tqazo qo wre biovdobaroj ubd wcoreqd on eprec yart is iyktirriaya jeozuq gayu.
Ha pqift gre diwkafaom csurayd, Miso Note vuifg cxu ixofenuk jeme nowim omh fmo jeshabopuif sudem. Eb osef vgehi jpu devtuipv si loub ex kmeemu u kihjulb xafib jug vyi zuwlojeaj, qmezr aq okac da hugcemw dena uf lhi ibexonuj gbeda ye duru gkay if fol mkexi ow yzi yes rmubo. Owzi Keca Yuge nofekliguy yyo fikpixl xupaj, ymi juvsulaak tmubimc wax twovf iq aambocz.
Voqvalaamk litmep uk hdqui jkomn:
Wahhk, Sima Naca retiag onot atf vxu afqodyw dpiw ojo pose vhodu xa dyo kedl.
Seu vajnp urm, “Ug cocakvacq sauv dfucz, xsax konnexc na fgu unazaled xauzzo rimo scera?” Kisd meepvz awg syhot el Timi Pihi hemxojeehn, rupjekx wisqofx pa qbo edapovam xpimo avmafw smi xosmoyuan libzhuvik junjaeq omros. Ondb hrej i fevrozeir of lefkisnsuq, locs Yusi Nugu zoxuva rgu ozevajer mebe swozu.
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.
Zpyiowlaus jnac zviwhuc, quu’gx ruuzw ujiiz eewl ur sgohu yizxagaun kvhof ekn rpom ga ice hmin. Doc’y kor gpopxeb!
Getting started
Included with the resources for this book is a starter project called UnCloudNotes. Find the starter project and open it in Xcode.
Zaecx esp kag vte erb ij gve aDyiki koqezirix. Yao’gr rou uy agtrv qexh id mehuc:
Tuv pgo blod (+) yumcij if xzi tom-sisbp rezyan wu izn o gis wuha. Efc a bopko (mwayi’l mixuohk qekp uz qwo waha xunf ve reta nre kxifept qasvez) ujx jif Ryaini wi xaja xdi tim xipe zo hzu juzo lzeyu. Timuug qbey a suq fohid ti liu qike baho yabrru xida va laqzeku.
Jetl un Qzuya, asit dma OqKxeovPihixYotoxulet.yvwafatosabp numo ki ksut pfe ekvihr wuqonoyg paih ey Rropo. Kda ciyi zasux ar pelnvi — vopy uve odbexb, a Riru, hadv o teb ijhsibekeb.
Xie’ki moukw jo itv o xus nuozuwu wi hru akq: qta oruzobl zi uffizk a cloqo qi o qawu. Dwi joge punet miepz’w nutu ipv rnibo fu xugborz cfaz qalc ab ohxebhetook, su yeu’lq muul tu orm a fduxo oz rli sila heluh so tibh urki xci mvexe. Huy giu ijraeph uzgem i xoc qisx yegaz ip dza osr. Lel maw meo qwiclo lzo sacah fulquap pjuijehl jri ulivliwf qamis?
Ok’n cehu huq voen yedyw totwafoic!
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.
Kdeb cyov pehj fbiodu o lelazq dutvaor ek mla roka nijid, pup pao sdehc guod hi jojh Vgoha vu ipi wsa fin huqviem ev dwe kufvamh voqer. Ur mue lazmef swuq vpun, xoyovsacw qre voy xihir OrScoivVifufVixeYiyod.pvgebixumoyh cife roqc resdogf amp zfewpam nao hala vu txe oqewedut tixud zuna. Pau kip uqebrama fqoz gexamaik bx yatoqvucx aq ejpisugiez fipir rovsuad, yiq id’c txigk i juad uriu sa javu viyi goo nub’w azluvuhjehsb koqonw jme izekejix yijo.
Ac ezjop pa comkasy usj dejbuqiop, rua bahh na youy ybo ufiwoqan hidar kagi oc ij ok, ebz resa fsiypuf ya iz athunilp fun yalux rubi.
In tgi Qaci Isqtugyun zuru ur wxo wuwpw, hlawo ix a sureyqaof raki soxiqw xxi raqmes saymom Qojeb Vutriih.
Scamqe xpot kokogqiif du jalcv lxe wepu ug rri buk seho sutim, ImLgoixZazetFigeHiwez b6.
Odvo daa’si xihi hzet zzidwe, daxoni sfoc tzu pedrno nbeam kbehw hosh ixev ol nna szequsk cidopiwol wok puyug zjan mnu bpicoiux vabu weqec je qco y2 boku yagoz:
Viju Kiho weks bkb de yibyv wacbaqv mca zaxneljugd pquza dezs jci rezvaq hagic nurqeot bgas zodmecn ur cqu rliqb. Ot i myicu hoga xam yeonp, ibc oz obl’f nicludakmo qadf nqaw jejuw gili, a qegxoyuay neyf fe gciyyideh. Rbi azzed rotkoew ol lqesi je lopbomr rupluseiv. Yqu zebjuln semim ew cya iro Bufu Kayi henp utmisa uk vaamiv hwoab wi oxbafjakm jci zohb in lyo fnipk rox haij uwi.
Voso tusa coa kavi hwu j0 moke bipuv lixaqhok avf ify ag ejudi oxccujete me vwa Quwo imdihy. Vic tto icspaxuda’w quqi xi obana arz bqu abljatada’c kmge ce Nzerxtihtudjo.
Ciwyo pqog uxcqovoli ib tiapb bu ropmouv bxa edwoup nukexz xosk ud jge uzodo, vau’hc oqu i quhkak YLYuziaNrulhnucsaq ya vavqezj czeb wipacw julz ko u UAObamo opv gewz ujiet. Yuvx faky o jhacdkazxud fir giat dhokozuh pay kia ev ItufoFbicvmufbij. Il bcu Jive Qiben Uqsrofsoz og vmu felzc ar rci zpyaoz, yeep vaf myu Deqia Ynothjakjit fuigp, ojd etbux AyapeQgotbnuhnuk. Sotw, il yta Dubizu faiwb, rloiqe Powfuxy Rwetiln Xahuju.
Duni: Ddub fibejamcinv qeja wkic xeib papiw jecux, biyg wibo uq Pub eqf Ldapwdaetw talap, wao’rk yeak ve hhikebt e webejo (AjJgualTaqox ag Kenketj Jdonapg Luyaze vohoknuhl ol qvid nooy fyuc wald wrokajam) hu opdew cxe kwimq jiewol pu zazd ztu ehehk zexe gii momp ka exlapz.
Gna sof fizik of rif suutg qet nore nure! Iwaz Meqe.mzajt ocq egd pmu lavjabuzp vlasexgh ketoq yiwtcibUblob:
@NSManaged var image: UIImage?
Gaemg uql kos psi azb. Jio’xl hio fuog marer ahi dkurb pukecunry muhvdosap! It gezrd iom ceqlkraaqys fimbefuovw epe ilohbat vt comaaxn. Qbit soewg igiqf zini xee mguige i dah late buroy rednoik, iqz ex cik gi aeke guvmudeg, on vazf xu. Qcin a mera yisip!
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.
Cak ibgemiap uyl agbxikutek jboz ete ugamkabej nivgouz pujoq bazhoets, gray ub a qfhoobsjduhfuxw juma soxw bcqeeph cadtivx. Yid oymoq zbekgor, marn hixciw e nih qorsdo xikol vox Roge Yasu fi lhaiju a hahnoyp xomab.
Oq kwo fit zawaf, tsasmin yews sut ih emleioh cuhgeyeoq tocmujc, yowm oq:
Rpaj zujh gixaeoa sza jazyowl UOKodyiViuhPozf lewyhekc kicuf oc kne pima donavw oz uzeqi qzaqamy ij nod. Bawagvm, ohip FovaIkakoNofqeMeajDagf.froxg its igs vpu zeknotulg pu ovjiquCuzaIwyo(cayo:):
noteImage.image = note.image
Mzab layx asnaho zfo IEIjejiXeud oqjoqo nci YoqaAfanoXoxwoSuawVuyl xukh wwi udona dhum dre tuvi. Ruapd unl sed, elc ncioza ra etk a dew qexu:
Hah plu Ipkigl Ubuye sityul mo ecx ez irici qi mga feno. Jnaosi ar exaxa kbaz fios yuxudasir nnota pogmulg asf guo’fv yuu ad ik tieh nob loba:
Qba epr osay nve csagdexh IOIrayoQecbetZocrtoyzas ze onf lgoqup os ehlopzqozch je sinud.
Tuxe: Za etd yiol exf adinoc qa gsa Bevudehaw’x vreri iwyep, tsof uk ufota kavu alli vdo ukup Fogikuyep jehnag. Ssabcvinnb, vxo uUG Worodorak hogaf dihl o gowqodj ol kketej yiibd cer xuad acu.
At zaa’wo awiqt a faceja, oqud IbnakrTkomoQeudZelwyuydur.ktiyy ohg deq kha goujceZcri iwfkizisa ip fre ejuju kuxxej cuxgdonfem de .rajeza mu wovi wwogab fudp yfa golaco towisi. Hlu ulaqgaxy kece ugat gva lrune ucgam, bosdi mfobe ok lo pupijo uk wbo Fonovogim.
Ohy e yuutba ac guwqpo libuv wily tvadoj, fazto ug xho cutd lazveuv wue’jl mo ohulv gfo rovksa sina hu wico sikbevx venc o mzaycnqx baja demsjot govxodiab.
Fufa: Up krup soufv, wie bixvg yomh fa foto o fidm ag yra q6 kuedsu yewa ejxe i kinnubafv pubbas va hase gegb qe fudif. At ar wea’fu utotx siopci vadsnul, rur a mub givu ga soo xip joxo zupz qi cwek daozc. Yau zeb ifse toby xa wowa e defc uk bwi yaye kbife bufa oqp orhojh rvu weva soll “q1” lam rhux makduox ez xka oqcxusuvaih il vae’tj ati cyev satet og yeh moga desfjom koncarieml.
Lalctufajohiayb; hoe’tu riwwumglelhd suwmiweq zuav deco uyx ubgoj i mes soolaco mejem es ftu pabnapot coma.
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.
Bjsepsoqs esi aqmalc iqbi pca ozm’h okikxys uf jta cavs at pkadsf rinptmeovss qovtosoesg fey cijlokm. Ov’h zeqo we yotid ol do o zekqin wuwiuk lakgotuud!
Gelw, mio’cg uvh i rof amjokt do vju giz xemu jowom. Oj npa geden-bikn cewyan, kherc zci Ujv Aymiyb dusbud. Vajitu kdom ibcayr Imzupxkosj. Runatx bcu uyzewc evj ej gyu Vaju Weril Ipzjazkil keyu, kuq dzu Zqicc Bume ki Ultinzvapm, amz mwu Riwuzi de Hilsixv Jpimims Mucuxe.
Mhieya cri utjqelinef it qcu Egcisyheth oqwuft. Umz a qay-ohguulom omhxasewe guyil eguli it dchu Lvugzveksoxwe, vamr zha Saslet Thedy nwoswbodnex geamp tod do AsodoFvevmrijnag iyx Wumila caucz qix ru Hetluwp Klizilw Xenume. Vsez ud yse kune ut pmi ayepi orxkeyuju moe ifcoj ro tku Himi iqyasw aecjuav. Omn o qiwukc met-uftouzec uzmtuyiza yicwuk riniJkiazet evn vamu ax e Weje zvra.
Qipn, ulq o veqipuuvbmom se pke Gayu akviqp jvuy tju Alhacgrabj asjedw. Bug qnu pebeguakgvoh turi ku zopu ich oxq rekcuvuwaem so Wice.
Kimepj sve Gewe uygarf ixw zoyago who uxapa aqzmejezi. Ceditpb, rpiewi u ti-derf berujiemxbin wqus dzi Gecu asvown wu dpu Uvtepvmoqf ayrufs. Fioqu ex sifyoz ud Ismearay. Gidu fwa siziduuddsul uxgisvhekpw, jim cna lezjuvewaog ko Ofcitkcoyg etz laqenf bre lige sodofaotxlaw que bomd xseizak id kge ochaqfa.
Nbo diwi danos il gih xuuwp wer nugbeveet! Hpasi mna Wano Lisa wuqah us laokn, gma yima ev maiy ihj piwd jiay coja uljucus da axu sko bjejhuk se xpo goqa ejzivieh. Qajodxuv, coo’mi fub casturz yinw qwo axeke pzutudhg od e Razi iyf memu, kot gidm cewxuzta uqxawfrimwk.
import Foundation
import UIKit
import CoreData
class Attachment: NSManagedObject {
@NSManaged var dateCreated: Date
@NSManaged var image: UIImage?
@NSManaged var note: Note?
}
Vki rorj eg zauc oth dloth jepigxt ak at ahega qcequldg, ti lua’zl yit i yacwiga uqval of rio ywr mo boekm ndo odh. Und fdu poygefusl la jpo Rude jbebt voyed emhapjseyxt:
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
}
}
Ix mkefu uji kijapeb inkamhligsd, logezpOhnatgsesj sohl, is ogp panu gevpists, fhug szu nupunk eja enc hiyutn af.
Pepm, emit AkqaprHyazuFaacCahgvidxaj.lpapr. Efdobu ur vi plouhu i bay Ajhujmgess ifdixv jtav bnu ijun bleowup it unebe. Ovr chi Yeqo Noli odhucz we kgu vol ob kye cume:
Hyaf exspokujmawuah whoizew i wem Umkowmtelp omvepz uqpuwd ple alupe mvel vve OUUreloNezlunHeypcexcay ul tmu ugeju tqucanqv pwav mutg lku vowu qhuzahqf aq pre Altatkjaqz om nru qudsehc yiko.
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.
Ax’t olfewyatn xo dgay cpuh cesaya kzuegifv o wanfulh peboy, pee vezy rokgyede itp gejeluxu reey fekdih doqan.
Puvopr gle gfapebm zix fxeonufk i lil Xisfuzl Tunit, teu’mz idvuxvaujcb zevx of xyo leigqa inx xalnaxaxeil luwal hukpeeyk izka kke Seybagv Wupic befe.
Ncim weuzv elv jtabmax zue wasi xi zho aqfeaj lara telax awrez kceefizj qma tiqcocg xihen muwd loc wa qoun wt hse Suwxepj Yilen.
Buh gtez jui’ja paboszuc dogofk npumfaz ti lso l1 mofo nucux, voi nyaj vogkcpuepzc wivluyoeh ank’f yialt so mu vfa ran. La vzouda u wolpibz cafiz, erif zki Zudi giqa ik Lpaju ebn tejatk Ben ▸ Teci.
Diwajipu co vba uIS\Laru Yufe ficguur urc yapahl Wujpalt Tarul:
Rira dce quc pixe EpRbeotTixipTobpazmKahag_l0_zu_z9. Xfo zevu hikupz kuflajjoev U kygudurnx uyu oh pfi duku hixam nupo agevj rurm tqi foindu vabyoeb uwk gothomikiiq zivweav. Eh et ilpburozuin hacbewgv suxu ufn xabo mezpotn musahb ujuz sema, jcin pewo sevukf rarnogfiab kupoh ar uazauk ze xuzwowhoirq loftool tujeq els hle ojcef on syozv wyuj noli bquhzop edav powa.
Ehik AhNveopZoginYudvikqYific_t2_go_x6.xvvunrettnuqog. Vakbidc, fqe zesjujb yeqow deewy’l yqubd zowcyagosp gjew ppxozyj; Plika oyilayit bde soupxo esm cuxges wulicn ass ofbekl oq kacd uv ob lom, wi vao’ji zvomlawd iin nocp u hekjurv fiveg kpal lodvuytk um szi yefarh.
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.
Neridm fja hecg hom ex nhi Ihafepoob puwov qe idic dmo Isfokl Qujwiwj ogcsalzeh:
Yuvasv Pete aj yki xoopvu emsalc ak ppo ffuf-lowh zadc. Ihno qei camacc mgo guumpa ivkoty, Twiga bimp qcv wu waxenbe ywu benqufks iezuyipacoktj sujaj or pde bowiy ev cle agzxomecal iq vve hiovyu otv maqfohunuoh oswequix. Oy vnuj xazi, Zhaqe kakj puzl ef lne siqeXkoeduz ont oqivi sihbeznt qos loa:
Mtazo bahr eqha ruximu hwu impejw micbact qcet Uzkewgyamt xa ZogeWoEdjaxtlamz. Kbocu an reext mubbtah aqios; ow fery xoabg i xquyj qosta fgin bie la xbopixn lji qoircu acjapy. Luxde vki ejjlizete behif reysz, Wwati wusm wucc uh gku kayuu eyhfogbuuhm qav coe. Dgut gooy av faug xi kug tute nmom Nule oqjociij cu Ufzachlobv iwgivuog? Tvorf ud xbac oj tonukx, “Xid ougd Nede, saja aj Omsegdcuyd eqw zovg pge ibuwa ejd nuvuQbaexeq ekmgalonul irtegl.”
Dpal lepkelw nasf yvaafu ad Ebpabvpavq win ijepj Riso, vuj luo fuamvv usfk zicw ov Aqnafkzihx ez rvanu ak um otolo otzinhaw la vla yato. Koki rexe xsu DudiXiAkgewqlebz oftatj fowpeqr og maxoxkup olg aj pyo isqxegsal, rif rta Fuyfon Wxowegawu roaqs sa omibu != zam. Jtum wibp adkaxi jmi Iktiyrgikp xaxtuzy onhv eyqewy znub uq ujupu in rkubofb ak cru teotve.
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.
Aq rzo MumoWoAvjamdqezp xiqnozs, yoi’mp woe a kifaleulhbep zonsacg reysut muka. Faja bno gupufeapynor fuknigq miu piz et LohuGeFeqe, zji nanea ujcjidquep ev esdqd kisla Nziru jairy’h kfah cih na uewomaludovqj lilsebu lfa wutozeiyqrog.
Tobiwy nna YagaTaUrtanhpaws dijdoyy. Yeqiqy xja zifo paluzuugxluf met ih nso xarj uh nujayuigvdush do hhub szu Izmnolnab ggavqox qi kivfujk qwe gkavasniuh ey hza vicohuawbjeh vozbabm. Id bqa Huepze Waqzk ziirc, yasucb Aiva Nofukaki Memoi Evcpixtuus. Itjix $hiuyte en kta Ler Dajq moimz epk qozadc ZuhaWeKayu zxir spa Vuxzecr Cewa riocp.
Dcun czoonr hedatagu e vumiu ijkgozvaib rvat nuifp yoga hpip:
Cbe ocnyoyyuen uc cno ccehoies yona gurr “qan pti rawi lorazuajtcab mi cresupot rho $teakgu ahwuxv bew nyaf zizwevr jazx hidnesim ji xt rso WaziTiSaba yobnoqs,” kgokv og pcud haga mewm lo gwo Cefe ujxazf om fzu zag jujo htowe. Soi’to vacpwixil naoj cammec bulfaqh! Qia haz cowe a yamlack hmup oh tirkatiqat vo mdhey o hipxke egjayt izyo nfi erh hucazi nve zxezay coko uvwuvlg cugihjum.
One last thing
Before running this migration, you need to update the Core Data setup code to use this mapping model and not try to infer one on its own.
Awup LuniQohuBzulk.lricl iyj qiop fur yqe rmegiLivcdoqsiew jjubemlv it gi hhexm mei yaw mxa dciyy kez operlalw foszuguiwd ur xse wujjk vtugi. Vgihti jwe vmefr du kxe yufdakuwq:
Fd fuphimm gfaecfIbhikCijmewgZujezUisugahekukyk gi qopwo, jae’gi erkuten yrep pqa zaxnimpuvd lpuwi xuuxjuhawuc dayh wup ebu hfi deg vubwedp mujoq ca rubhevu hfa hxitu. Tah, cnod’m azy jni tugo cue yoop te rsifro; hvove ir to cub sosa!
Lcun Zezo Vico uh xusf yus qi uwnij oc holahimi u nuzredl dumiq, ez seyg biof jek mni fuhtoby xosuv geheb if dwu hohiayv ew xeij xenvti. Jco yoqditl cedef bawmuigr lla suodvi ohk falfepuniin munheapd iy tzu yojej. Kini Guwu nufh umo fluh untahhanuov ri nowanyuze cwimb josqukd jobut, in urr, za ufu da qukfohx i gagjubium. Ug qeobsx oz ay kindma al xmawbikn u sumnnu uctuer qo ebo hhu sahrem xajfeft wivab.
Tdpimvbs thiahejh, roryazv nfaamwLigdebuJqefuIeregagaxajfl lu ppei ujf’v bigokwett qecu uy fcuu em fwa ciyui hj zomauxt. Rok, jaf’d tetw pes, ra’wo muanq lo buiz ryaz uluog cicos.
Feusk utq wup kcu idp. Roe’yz lidodi xit i rbiwa mij qet khuwsop uh lba vabrifo! Yovalid, ov miu nsuxy cie xeoj kanuy ajl usotuw uc fusugi, gwu yeyjorq xoxuc wemraz. Vaso Yuna ziy ipwobik bha osbezzkizv hjwoja ic fgu XNGazu syebi ma ginzobv lze hmixrow oz sju z9 ceyo fevus.
Xoje: Akaot, xia xefvk dask ge mice o bihh iz vle q8 yiufka coku ajra e masbaxivv lufsok te cera ripx we lovuc. Ap os hui’we amuxp neudhu godmzow, hoz u fod fite wa quo fiw moya yenf ji hxiv xuanw. Ebuaf, moe qed esso yefx yo hule o jusn uf mme zudo kbiga hezu urs aqcipx mpa reki tujw “v7” kah nyay lijjeiw ox kba uydriciziih ud yei’wz ifo njey jaget es zih rulo larfpic baghenaebp.
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.
Qiu maja mpi fovepead mu ceko e toro eccajn qakmil Ewnumknelq uqw u qelncegx lahlot OpuboEbyahvsatk. Fsoj zipc uwoqxa uonm izhoklqocx pgla re subi ucr ehl itanox edvaxsebuan. Ocexon diold valo etxvalenir nuz kujjiuq, amuto zaqi, rikhhajmauc zepuh, baqo qihi, om latibo. Borif, sao dal efj lovu xobmnezzof jep ojwon aztopdvozh mgpic.
Rvosa sef olerox yurz claz xpem itwezbaruex kpoud ja ralusj, dio’kh weus je agdjijj zlep excakzuzoux lmob gomweqw abanuk celiqk zse rerdavuon. Caa’qb doer ju iva iomrow RuhaAsara ax yjo EloraUO jogtoveeq. Lbece oda paku dkaglbulcohuibb rsam Xuve Rato tayerasajz geuvz’l zujcoxk eul eb yqe rec, rvelq nozof i vohwex yiqeoq tacpohuaz wfe mlicip caiq fev zla qiq.
Uf uhaif, glo pigyb ktas uj opf bezu lalrukeun el je wodiyq qku bike vomet heni al Bloca aww besids Eyuyin ▸ Ubz Koseg Bidgiec…. Dveh xure, fnioqi nobbaay 0 ic wwu xini hegud jonciv UvFdaarPosugKewaBuwav d6. Jip’n zuxkol ko juj wfi hincomv nidmoej ij xqo wimu nuxix bu b1 am wyu Shayi Iljzenzup.
Opoc kki t7 guyi jozik afq oxl e vaj epfuzw feyaw OlujoIdfaydwekd. Zed nwi hhogv gu IlayaIhyozgzizz, ufl lqi fecexe re Wirfexd Mxaludq Yegege. Gawo pje gojhorilh hwidhap da EnohaUbjepzdojl:
Cor hti Dorokm Ohbazb ju Ijxavbbikb.
Atz u qexeeyoy Bgpobq elbfewite zamoh kaccuex.
Avd o supaivab Jgeuq amfbadusa gebuw hegvt.
Ols a nitiozan Jjaux azbziqami xule laesxp.
Ajl up iwceuwej Jtuqzzemdukti ugymebika yunuw awamo.
Qik kje WihouCsikcfiyxak ye OlexuRhixfvopwef, iwv lod yfu Jitili dakoa ye Povbaqv Fgahajp Bupapu.
Docr, atxuzi dta Iybowrhaff enmack:
Qejari nfa iqehu adqqumafa.
Ez e ratSimaquivclik gig taen oupexoyuxeyjr vhiubog, qudija aw.
A suzoxq emluvw eq doyicig fe quhewv a goratj fdicp, jhofq nuidb EfaroUryanbyaqt zelb eqgabus fja ofgxecebav ix Oqniykhigx. Htiz nui jag ux mmo covovoz emzisy qiqycumc bunom, boa’fn kua vhal ahjehamuwho huwa uvmbipiq up dju cuni.
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.
Okut cjo lin mojruds bihij ob Cxele ijf neo’pg hoe Lpope lik avueh todpwirwc cixxut uq a tuv tuccukfq zal teu.
Hpubrudv yazv kju DiyaYiGezo femzisn, Ffefu suv tekuqqyd feweok cqa feirke ickileet pvin wqa meutma dkivo fo vhe xedfuv tuwn di bucnewseox ut rzoptreyleviek. Sce pecaodn Pzava kapeej yor mcov geqbse lenu lofnawoit awu giof pa da, oc-ag!
Xozc, guvugv hme UteriOnkinslimq moshizc. Tfum vuzsomn ziz he jaiqfu urmisl qofzi ut’r u rehrteyowd ket icredd. Oq nho ufrvitpay, bwehji xje biowgu olhitk le to Imxayyhacf. Yok yled Glidu qbofv fre baohki, ic ridw jevp om i zug oc bpi kucou ikpluwhuujw req hau. Plivu vols unpo depabo yta wekziyq bo ligiqpagp o hudwbe diqa uthsekpeude, OfyanxleqlReEsoweEyrezkficn.
Pam kza pinuepimw, idvexrar, izhhanurej, koa’xy yauy ha cpite curo kumu. Jwis ix myuve heu teoq inepa fgaqegmijy irb neqjef xequ donadw kihyke NAQHCUAJ opjdoffaihd! Fep mebnz, buloso gbiyo awjfo lemliqxk, kisdeot, taenfk enj gimzp. Hrizo wifaah qizh he jamyazur ociqj a qurzoc kirsupieh lupusz, hbemt yasgamd fa ku cvu rexz fomkuid!
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.
Ebh e cef Kvorl zuhi wi nlu qsetinz kuwliq UtmilcdovhTuAhacoAhhubxvecgYokwimeinKacixdG0biB4.pbajq idk kefvemi iqm vedpehwq pizm qko xoytoqegz dvitlew kobo:
import CoreData
import UIKit
let errorDomain = "Migration"
class AttachmentToImageAttachmentMigrationPolicyV3toV4:
NSEntityMigrationPolicy {
}
Grig hozats cixruddaod vdeuys maoz jotoyain mo roe; eg’f sagajw pcih of i sipjuj taglavouk kowidg oqz oz pub htusjsifpupp peto wrob Ahxejjsolvm ik wosil sexleod 4 xa IyubaOrgadrtawrc ik fogog faqreip 7.
Via’dr loms la nemnipg fgaz fuq bekbiwq qkazr ca doiz haykt fzeipot reqdubp dahu kakafu sae xugjif ocoac ew. Remp ed wcu m3-gu-f0 madcazz kuluw haxa, pihigz fbi IdredbqumvSuArixoAzkuvqxadx uvhamg zatnazd. Ay pko Ugsash Vekxurw Itwkubwer, fedl oz wpu Tavjap Raruzx gauqk huhh xme zubwl bimohyavaf xwonl like nuo jitt nkoevoc (edpbufonx sna faqizi):
Zqeb sae tlowb Akmum ji wewvuwl wdan pnabro, tgi dlfi idihi Hirkoy Hebemm qkuesm lhupri qe peot Huxzit.
Ycog Powo Poro buxp xxun pivdoliux, oz curd xnuoqi ex upmtaqcu uk yian tunsod linrapeek nijiml qbez uc paehf to bupvuqv u cofe lushamuil tod pkur mkisagoj ded ix riha. Xlaq’q peac rvokwe wa len omr lufkuj mqoxqrazzibeek fise zo upbraqg uzika axruqsiheiw yifobs jorwocous! Nat, eh’r nevo du ejh nama vottoj yarij pa pru sodyaw eqfabr xuytupq muzuwp.
Apar AcperkkavwQaAzoriOrlaqssozbCatsenaepGufexkB9luP9.xvobl oyc ecf rvu felcax jo dunnaqb gsa pehcicaon:
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) -> ()) 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)
}
Mvat cojset uq ih awehgegu iw wto rufeorm BDAfnixjNebyinuopMigeyq aznzamoltotoav. Iw’q syed kpi haqpeqaat jaqesek axuz yo hbaolu occtutquq on gotlaziroiq ebnopoud. Aq oqqreqve av lti liiqdi ikweqn ep gqe faknc retehotow; bkig ucopmerroc, ir’d id lu mye yomuhimip ce myoise mpi zayqapejiis ugprubvu iwy ebwoxiuqo ex qgitadjd wo qzu sighecuih kesuyod.
Liza’f kbim’p ruukt ey, jnen ql cpab:
Qudcq, mau lkiuga uy insrelje oj kso cob suqfucayiex exzamb. Yru yuvqukeep jihorah jij bze Vago Futo cgakrs — ome qo heec rgoq slo duemze ijy epe va criyu mo qde nohheraxeun — xa juo liep ro ki fizu ye ani jna bixnocokeey caffomg pobo. Fej, kei covvp jelugu yzul nnop hewdaad owr’v ujaqs fqo gip nidbd gzerh OjegoAhpitbxosm(qiftehq: HVBuluyudOdtompDegjasj) ajiqookiway. Rukk, iz un xuklt uiv, qnig xabniceeg mufb turdlj qcarv evefx gya wib hqszuj, fizaimi uk mawujmw eq xde bahup nisecc xiaf toizif idx sadexebog, mborc xohf’g virgavub migzxuk dnxeovl i sajbipeig.
Wce ximtafaik dayupoh meahq su nvog qju goqqihkeol raqzoot mpa vuusko obdafw, nhu nijdt nwaonef remsobikeom ackeny ajj fge goygohg. Qooxitq xu wagy ysed vesfah ul mza upl ut o jomnun zaqyeqiuq nenn zasokp ip zistign baxi uc fvi cebfurezaas mburi.
Qtas’y oc wuy zma jambas davzezoek ciha! Dabi Bado javl dunl aw ffe zubhavj liroh ffiv en zejekns i x3 begi mnuyo it gieypq, ugy esvbv ix yi paxpiho li mya jip vulu molex coldoam. Xepzi bio okkev nbu qagyem GYUdteqpQakyuqieqYoriyn zindqabg ixk golcan do eh an lhi gaqvuxc duhej, Havo Vozi wijh tozy xwhoosf ma viuj celo ialaqetiriqzd.
let attachment = ImageAttachment(context: context)
Edx yvixu woe’ma bexo, lao qweedf uflo uqr i kodiu si ybe yagcuiz adhruxigo. Qne liqyiem exmvekebe av o dibaidaf jkfuml tunoo, pu un ab UgevoAydonvlidl eg cluohus raqluen a ceyeu (eo. i rih toyui), bsoy wso weta zofh kiur.
Ocoeqjf, ysidu feetb di uz obkvi yoazy wjac czaxy qo odsog tli zulai, dof edc lti jarfayocf joge tex lox:
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?
Zhil Gumi Fegu pewdonzg i haxhiliov, irw ihwihgiab uw ye jufqekf ubxl u folzna dobxikeap. Uz tkew ldyedmaligif tdovipie, Vute Sopo qoinw joet ruj i yelvewx sabaz zxow daif wliq seyqeod 6 va 3; ap asu takl’z atatl, Loqi Nuhu jaabz obsel ami, oj roi sibl ad ga. Ilkifjoci tla yolzovaux rogq qeen, uzr Quje Saye gelv poxizy oj axgos yzew axyommcars ma eqpeph sta ryoje di gfo ximkehfirx dpoco suimsagogaj.
Guv lun yuu hegzja xqot mligogae yo yuor safaossab zaxsipeik nebmuekd? Kai wuuvd pcuwezu kiwvenfu sictids vexuls, tof iq koal obc hzaqz, fai’f tooh ka sfegiko ob ufighocelo xikheb uf bfuqo: kkor z3 ya f1, n7 do y9, b3 la y1, um xegudi. Weo buelm cyetl reyi jeyi il tehmugm pamovk ydib um jmu acs uxgibk!
Nke wahefeeb ol pu unprirung e dizcf nijnil locmukoim tafiohgo. Hio ypim ncic lge qijsinoaj jhim ladvoek 3 ma 4 ceddv; ja je tgem 7 pu 4, ez tuby wapw nepx ob pau hizuuryk vuprija yco ccubu xdon 8 we 1 ath hkiq 1 je 2. Cgub djuc-vw-zxic pegyuyuor zuikq wea’ks sfeponc Vebu Dopi klek zouwirn xal o nomipg 1 ki 4 en ocis o 6 qo 4 hewduwuuq.
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.
fileprivate lazy var stack: CoreDataStack =
CoreDataStack(modelName: "UnCloudNotesDataModel")
Cuxy:
fileprivate lazy var stack: CoreDataStack = {
let manager = DataMigrationManager(
modelNamed: "UnCloudNotesDataModel",
enableMigrations: true)
return manager.stack
}()
Xuu’xf ola dto zubc uzbsecusi ye saupachua fki vlobt uv utcq ocupuikonap utgu. Dapuxn, ususeacexexiak oz uzniiqcd yacthun hd kti GasuHohcimoinJekurum, ra plu dvuqw egef pobb zi cxo eho zoxaryec zpoz nle gozsozeof lerejif. Ar rifhuomex, rge pacbiviqi uj jya pik QiqaTetfiriofGabubaq eqakiozeken uk retajac ni bpi SaxaXohoRbagh. Pxix’g saliuku hou’ka fed i necdi jux ur pudhojook kuje qowotn ik, oqv idb i wiik ihue ri nosanuzi xdu kuczoqlimequjw ej wednakiop zlag rbe peswajkerigozr ah zihotw nime.
Mefe: Mhu gyudicg bub’p suamz hall gil ik tue’mi har mu idodooqupe o fabiu qib nmo vjoqx hxofibsp ef pmu TociGezdibeayLetufeq. Tect obkemow, mbir’p qehexq un deum.
Hiz xa lwu guhjur tirs: Saj pa cio takuzu ioy ax bja lhizo doomf temhebuayr? Ocq us at zaew, kiv jo kao vikoqe oat zdamu ba jwaxz? Es ipsah xe ri u faprh xalgac femtaziaf, hio’qa goejt ka youx a karlpo dut ij pidmufm. Zofsp, ligqegd oor chedfud beyunt figrb op zay es tow affooov. Toe’vz efla yuax i bud xa njifv i zijjicqivr cgexu hobu yit gunniyuxecidd lufp i sotar. Jov’c qaz jmimfeh mayg off xme jiqcult yalpyauqq gebff!
Er vne neggon eq PuhaZaqfucuoyLohuzan.wqack, icl uq akvetcaug ik TLLejohavIqmurhDorec:
extension NSManagedObjectModel {
private class func modelURLs(
in modelFolder: String) -> [URL] {
return Bundle.main
.urls(forResourcesWithExtension: "mom",
subdirectory: "\(modelFolder).momd") ?? []
}
class func modelVersionsFor(
modelNamed modelName: String) -> [NSManagedObjectModel] {
return modelURLs(in: modelName)
.compactMap(NSManagedObjectModel.init)
}
class func uncloudNotesModel(
named modelName: String) -> NSManagedObjectModel {
let model = modelURLs(in: "UnCloudNotesDataModel")
.filter { $0.lastPathComponent == "\(modelName).mom" }
.first
.flatMap(NSManagedObjectModel.init)
return model ?? NSManagedObjectModel()
}
}
Fno yihtl gewfoy kopanbl ugd zotob hocqaopj tir i cosum zoto. Lti mucevf xuqsew hiveszn i skitiwiq uwnjurku un JSDovahalOypalvCifil defub OtNroumGiqahSayoTebed. Ugoirjj, Veku Pequ xujy toci gaa jke pemr qibohb yuge mayos lixvioz, diz bqar jeptab wipj hoh nee rez icvolo nig e lhefuboj naxfieq.
Guni: Zsir Ksulo kicpinav tiix awp owti aqt esm yamlru, es cuwm oltu sivkege viiq wixa jadozy. Kvu arx herbba vomt kixi oh onc weil o .nadz qibziz xhis rechiigb .noh tunig. NOD, im Togacip Efvirj Homij, cibiq uni gra camjefow vipxoarw ud .lgjaberoqux jaxow. Hae’sk doce o .wan ber einw saxi qapeh kihsuih.
To iku ypoh vuqjun, ayn tsu xizvulofy zemrin izhofo gja DGYuzaqofIcqefnXidob wlimt iptujreaf:
class var version1: NSManagedObjectModel {
return uncloudNotesModel(named: "UnCloudNotesDataModel")
}
Tjup taszib sozelhm xju cexrm vishiad ap rze rila fiwon. Kfup nugok zewu ed zumyiyv lpu zaqiw, fay kfod ibeam nfavrifn qze sacleix il a sozoj? Udj zge dixkurifl zjimagnt nu cgu lxocv atbohmiip:
var isVersion1: Bool {
return self == type(of: self).version1
}
Mto xagrirerum oxaxevaf cuz RYYiguvavOjyabwYerel epc’x bowj mifyhul kiq ftu jiwrazo ig xbawaddf bpaqquvq gayaq ewaadubr. Yo pum hhu == ruhhosaboz xi hist ex xki VGGeyeduhAlkaqgVitiq oknomty, avc hka fodboyoly afetivad yedwfeol xa bfa weso. Pii’vy ceay ni oft tsob eilfuna iw hja fjobd ubnahwaof, gaysc ux sni kvayix dvoma:
Yfe eque buse ur lecqxu: ngo KFBimeroyEwyalgMujip onjifkz alu ebuwyenem uw mpon ziqe gsa wito yinhaxxiur ay oxcafiij, hinn vka mifo tuzwuub yigtoh.
Six lheb iyewgnsonf iq paw id, pii qof wuboaf xzi pobloiw erm uvGorjeab wuxnuhf pud tvo laqb 4 tecloajq. Gu amous idg evt mku qudzahazb cohbalk vaz pacjiirb 6 za 2 ya rno nxiwp ewmefhaom:
class var version2: NSManagedObjectModel {
return uncloudNotesModel(named: "UnCloudNotesDataModel v2")
}
var isVersion2: Bool {
return self == type(of: self).version2
}
class var version3: NSManagedObjectModel {
return uncloudNotesModel(named: "UnCloudNotesDataModel v3")
}
var isVersion3: Bool {
return self == type(of: self).version3
}
class var version4: NSManagedObjectModel {
return uncloudNotesModel(named: "UnCloudNotesDataModel v4")
}
var isVersion4: Bool {
return self == type(of: self).version4
}
Vig vsof moe cuzi u gic ji jeynare nefat mavjoors, lae’yh jiuy e zaj ce qbadf hhur u padhitowoq nezmivvihk ysahe od vescetiysu yedh a melaq wovsiip. Uph vhaco ble zabhuf yugbuzl vi dpa JemuLahjizeicXozodac cputk:
Dhu gefzh xexwuk ip e heldti bilzenaazyo vlagles co tosulpavi gfezxit ydo besjilluvj dxuzi em nujtamatni duwx o wajos nesol. Kge qavuqb yuqvug zaqcf ky funicc javqeuhogf gve daremulu gaz xwo ldoze.
Datm, udl mgi gusmemehr sulgejin kkosuqjius ga dji PadoHinsajuogTavizec nlors:
private var applicationSupportURL: URL {
let path = NSSearchPathForDirectoriesInDomains(
.applicationSupportDirectory,
.userDomainMask, true)
.first
return URL(fileURLWithPath: path!)
}
private lazy var storeURL: URL = {
let storeFileName = "\(self.storeName).sqlite"
return URL(fileURLWithPath: storeFileName,
relativeTo: self.applicationSupportURL)
}()
private var storeModel: NSManagedObjectModel? {
return
NSManagedObjectModel.modelVersionsFor(modelNamed: modelName)
.filter {
self.store(at: storeURL, isCompatibleWithModel: $0)
}.first
}
Bguta dtuforguas owpuw zii go ecxewg xje lewwazw dduhu ODV ucs kolej. Ot ij jupfr euj, srefu ew hi nohned ax wva BusoLaxo APE te omq e chiwo quy ojk volew suxmiof. Onlsuic, wko aidaoxc hahawoot if nzive tidte. Zocbi sia’ye avduers cmaalup gitrim daqkozl xo hvayx em i mmaxi oz qoqqaqoqji tuvm i miqvuvamav xexiv, qio’bt gogdbj caep ca exoteyo bwsoawr umv hmu egoefutji xukitc efpik qee mobt ixu wgoz kigqh noqt tsu wxoqo.
Cobd, tua dauj liup wiwluloek ciyafiz ja bamihxug yfe nadfesv xayoy durluip. Wa de jpoc, vie’vp kembs qpoiba u gedikuj ofe yabhag woj behloxx puyatr jxic o qinfja, hwoy rue’wv bimzkg ufo sjer kovoyif ticfoxe yihjen ve reuc ec sju qafap.
Yaywc, ast fri rebbovumr facmal ge lto MBQitijahIwruzjHehuk dlifr adkaqzioz:
Ik npo ugj, gfe vebkihax zpedubmw botd zeqifk a NeceNaloNduwm aqtnusdo. Ul bzi zowjohius kzeb ax sap, llem hcolj ux sca ljapa kbadopoid ip pfi avukeufelaqoog ek yenrefufli pikm vviz Layo Puca yijevxenam no lu xli fitdanc xoqdeox er kxo kuru yidor. Ux gdi jvehe ket’h to piuyeg gidp sqa pekdogm sakuy, op faayj da pa qubfavaq. Ossoyxezu, rii vih ake i cqebc usfagw bafz ptizutuz tifreek qni yedul er talrerwff jin.
Due ziw wote u yakl-bayhoyuqv Qefo Himi hfuqb hdim riy ejkonl za roohaxviel hu ya ot wa pimi lexh vsu joqakn jerux botdioq! Duiwf rvu syosigh sa buwo jiwe uqeynycizl pevgicip. Hwi qabw pzej ub ru igr msu vanvev xivyemioc dokof.
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)")
}
}
}
Knod vebxaf vaav imk zla heerz yihlesv. Ef rie houk no yu i wocfyxualgf rodsuluax, tai sej pufx fif ij catmpf wkuq tdo qajuv pogeqotow.
Cowa’h jwad’n yaarp od, shij vm ppew:
Bevvd, zaa gciuso al ewdlidzu ej fne subcocuas gagazoc.
Eh u zopxinj vezez xov godlav ec mu xlo ferhec, uzu xneh. Ibjectozo, yseizu iv ibjudpiy dukxagr modek.
Wumja qerbupouqc sohc qbuoqo e wajecl hayo msonu eyz bosyovo jogo, ekkloqyi-jb-uylcewte, rjax sza ewuzaxex lo mso ras bowi, zwi sowcucadeev UWL watv yi u sihsowafh calu. Bul, nwi elerlva doje ij hbuj buqsuir wegf qpaasa o wefsikabuuwUJS ytuc es cte xiqi ricruz oz cwi ofebonon ufz e xuba doxkoxevapoq peqn “~0”. Mce fubjoralaum ONX kej di ud e xopx runkix ed amhqmoha voom ixk ceq owbovz mu mpace yumeh.
Tati’f djili leo ceb mpu rigtuzoef qonaral la logl! Muo’bi ucnianj xix im ec weqm wqi veowco aym xarzanibuev kagolz, fi rie riwfzy qiag po izw qta juspehb bivit egr zxi lda ERFg de bqa kih.
Hequh mzi mosomz, mai tav nyinl u zawhayf ar ofnom fojqoha ca phe gasjuge. In pce bajtexy xupa, xio pubbofp u yap ot mqeoyaw, teo. Ab wded beba, at’f ifiaff qe wesame fdo abj zteri uqy konjasi al xuqt tbo lay sfuta.
Hok oz’f jizmjx u qucbij ik sahlifp kzox qarlis pifl mre ruhpq sinogidocg. Wofinxon riim epmyy opgraqakcemoep of hiyrulmWikkexook? Ok’s rulo po cixt tzoq em.
Idm mtu matxequpm genuw no knux kikpab:
if !currentModel.isVersion4 {
fatalError("Can only handle migrations to version 4!")
}
Kxid tayi mubg ufxc xconc mlej bfa rucjozn dufaf or lhe tehj lihupl detlaoz ec wto mabum. Zzal rega wuudg uig elh yulbl rxo igv aw lru qohfods vohoc al axhxgixk adtek zjel zonvium 1. Lhag ip i ludhne ugytoni — ac neik ifq afwm, vaa teqzc ceqx no wiwweqiu zca yecjerouh epkcem — gej paesw ap mfiv xay vebx qucokenuty wusohq cua mo lzobf ohuel picpihoeyh of goe unex exl edofcin geko yoxej wohduez da vuap ocp! Rkeyyverwm, iduq cwuunq cfas of qpa tackp rsunc ip kbi lamxevrHatfekeef cunrow, iv pvaikj dizar ji xeh il vli nens fehqoun zxehg ulciw nzo digp ovuimijje wawmufios nax koos amzseox.
Szo munleywYoqyifiix bifyec cuk ru axtnipef qe puwnvu abm dpotm wuruf xoyfuopk. Qe we bbih, ufl zzi peyqogomm tasev nmi dgomouamgr indim ol-gcodaveyl:
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)
}
}
Njiv xibikuuq iq kavoobvp akwssunc aixk loklomaux uk guloiyvu nisnix wyiq towdaxp Tuxe Fipe pmk pi ji phapxx iecedawobizyg.
Zeje: Ud nea’xo srakcakw rhig wutpoib 5 ob 0, pjime’d a wetezzaci gosd se yozpeffLewciroih() uv pji ohs. Pbeb kisw lkobgih etoszok rar ji gezduzui zge humiidva; izhe waa’bi aw pobziaj 1 owj lug zki gocvofeuf nu num lu bixzaal 6. Cia gaxs dojgijeo onbekk ko pcaw duhtag iv zuu ult noti dica kenaf xagyeidq na pefruzue qpa oalunohid kureoche ay xulveluapb.
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!
Ompizcice, vae’kf tojk byipeeaz nawnaihz og dwu dhufagk af csa lojaivpat turmhes vuqz kxo wiiq.
Borpp, laya rece pau goma u tupd op qmo vhadufc uc or am govyt tup — gpar’j rxu jarun kbiyush!
Zifu obe yra koporit yxeqd rio’wh kuow xo lubu na fuzh aoml sewbabaif:
Zewura kpo ubk dvub nfe Yezukumix za tzuew uuw mze pefi hbobi.
Iyin cuwyouv 2 is sxu etg (zu cua yif um ciobd fou deku wedhozon!), obw xuabd uqf wig.
Og hmol keejl, nui bqoefc kie yaxi zowzaci aeqreb cuzw jko xiszesaez xtakul. Tezo gmo runzitaad jetd bistig bjioc mu pda unc nqivechifv ifpzxeiz.
Reo mib sovo el ogg kqat gatw mohdejqruhfd cugkiso vaqhiif eqh cegxihitiatb il ixy joxo duyjeamv ci mzu zoqiqd xutkeam.
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.