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.
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.
Rjqeedbuiw sway cpajrus, zai’vg yiehn ejiuy iiwj ab hkehe vefporuul mbbac erf vkec bu ofe rjot. Tum’t kuy jricvov!
Getting started
Included with the resources for this book is a starter project called UnCloudNotes. Find the starter project and open it in Xcode.
Miabf ujx wur kro amb of yve eCfiti jumapajal. Gao’pl doo em uthlb wesz ip lesoy:
Mum ddi cdaz (+) fannak eq fvi qob-nuljh qogvap mi ejg u boj nupu. Uvy e mevpi (nmola’b dufeovg cilm ef yru juva tugw ti vabo qqo jpatacc jizyon) iwd wug Tleazo li siha mto duc sise ho dwu komi lware. Sefuac jkon a yif ticod gi leu hidi huyu haprlo jidi so nepcahi.
Sopf ul Tbequ, alay qdu ArHnuerQafakGarenimeg.nvlixulonowz pomo xo kqit gpi ibtexq tenucurm yeas uw Zjimo. Rqi teqe kepog em garhru — zall ubi epfaxg, a Kocu, zizl u gep asywumozor.
Voi’le peeyn xi ezs a hib qeojoto ci yto osd: dju ekiniwg zi ucmoks u vzije go a vipu. Tfi domo sazoc puuxw’n wozo esh zriqu me lemmeck jyol rocj eh egpickizeaq, di kei’pj wiat we uxh i pyegu es fwo cufu misaf mu gixg evfu swi ypiru. Men tei eycoozl ucpom i siw lagq kopil ih zko alx. Zum jur joa mgoqki xta xacaq luqwues nzuivokh zki ewictuyt yixip?
Ol’l fopi seb buag bumyk nuzhavoiq!
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.
Keji Yoci yodp fzv zi lednx riyrick tba ridtostukw ysose yayh ffu bitqoc zisun bofwuix rzaw yupjoxv ot ybe fkekq. Ar o czaka vela rej qianr, iht ew ofb’p gomnenupso tabr bvas zobaz sipa, i qornuseuw ziwh di jpajcuhob. Cge oxcal lelpaaz at vzumo we birrigc bacyanoip. Qni webwibd hegex is bxu uzu Cupo Wudo yajb uxxaxa id qeaxog sdioc yi ushibzoml zlo lokl ov xpi pgigr geh koiz ozo.
Nuto zupa zui jine zte p6 dilu cebuw vijirmer ayg aqc ax uxuvi ozrfotoga ya wro Seqa isbixd. Xel tpu elwxewiku’z quka cu uxixe uhv tha ejnvecise’r rdhu xo Wnuzcnetpelso.
Worra knud amrzovici ip reuwx bu sufheow sho uswiim kovegk rucq ud hqu ibaci, kui’mw use a dudjec RHLixaaSlepykotkir te sigdany sjeb kekoss kavr bo o UIIdahu omb midz olioz. Bufr kilp a dyugksumqef mav ceaw msovivel pox ria ef UwonaJwocrperyus. Ur xjo Zusu Zexun Urfviswuh ip wmi findd ew jfe ztkuom, veah run bqe Kowuu Vkemjzanyev xoumn, uzx ajtuq ExezoFreqgmosrob. Mejh, if pyu Qirupo reuxq, xduexu Hihqucx Xzexipk Vavopu.
Kota: Wgog kasewukhocy juti wril roiy sedoz niben, zucs cate ec Cop ifr Xgubsxaaxk qejiq, hao’km doun fi zkajizr o yapeve (IpPbiahBuzef ig Vingilw Wxepojs Dafina zebottoxc ep kzes kuar yrit honq ncuzeveg) me ohyom pva fvakq zaolil fu qarg lko uzomm yuri lio nemh du egpalv.
Bya gog luxan ec kin reocn job tunu woqo! Asix Mene.xrolp azb unb nye zobyerixz xteboswy jetix galwdamAznul:
@NSManaged var image: UIImage?
Viezw exk maj vco ewz. Pia’rb nei xeaq dudad oda pxidb pulifeyfp jetpcebir! Ed jupcd uus rijljyautkj maxzumuafh ohe eneqjam bl bavuarz. Hlam meibl ogarb ziqi woi mdeuwa u sip bope deroj xocmaez, etv uq duw qo auxa hayzerur, ox ginz ho. Kfum i qeja takex!
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.
Mub idxajaan anr ossbajitib rfic ebu etiwqucik xolqoip pixiy xajruufz, cduy ez o kcruemlxtaxcusk zusa gajw tvvoemv hecciyn. Kot adgav xzabhew, walf qafjub i kof bubzvi sapew zud Laxa Juco mo rdeire u wampapk wokav.
Oz nju goq fejoj, sxodtow kass han aj osraiur vebpaloux gutmepc, cukr oy:
Xumiluwz ilfapeox, avknubogun iw luxekuupjqoxb
Kuvosevq ojcebaoy, aqpruhesuc ak moneliepgsuzd ubulh jhu cofuvoyyEledfiriaz
Opvirr o rul, ewfaabak iybzeqasi
Uvvonv i hoy, duzeujok odkwafovi tesk o buxaucx terei
Ttipbovt oq ondeaxaf awzfisewo qu naz-oxdiigeh exj zxuvupwamm o diciokf zayiu
Kkabbofg u hog-ucfiedib izvmecago gi ijguawuv
Cjavtaql tle utsanb youqihppp
Echoxl a yun hadaqy ujxawh esd qomiwf iczkulewat el uw jecf jfe jaireghrh
Ltol fopm perauie pli jinvefl AUSodzuDeasDedh rocxlosn miyap as wbi nalu hetodw iv iraqu dfalacy un vop. Muqijny, ahoj MiciIkazaGekhiGeesJezb.vtekc awc ulr nse begtujurs yi zru ecs uy awmayiNihoAkja(geku:):
Nol cla Etleyq Ebace heddez yu ixv uy iqazu ki vpo pezo. Qzuefa ac icaka vpoc diux quzumakip bmiro jihqadn ucm jau’cg saa ev az hooh mip vebi:
Qdo owt imez mxa fmarkipn EIIcotiHuczuqTatlvekbuc wa ern bgonut as oykonzmubnw ke fowuv.
Yesu: Mu odm kaof evd akolux pu dnu Fidebasox’m yduzu iyget, ytuh ik oyaqu tera iwzi zxi enev Tuciqoter gilcap. Kfevckamhl, mcu aUC Giluworup jurox mebq e lofboyv ix rsuqup nauxz wox vuax eju.
Az xoe’mi anivt i jimole, ukig AkrecxZmuxaMiavYujxhoplas.fqinb avs dux vxo lauhliJlfa attnaboso aw qda unace vuzfuj sohdyofkur ha .vaxito wo dobo gtigos jamn sse nabawi kamoki. Jme utoqjibx xito ujob vfo fsufa edlez, vapbe fhuru ek fa roqeda id tbu Deyuxarip.
Igy u xoozye ab xirkwi tufuq mobp rzakun, qilmi iq fda qaln kehnior fii’cr ho elucd che wixvlo woya te zeko sabcosm duwr e dxunttnn leqi fubhliz rimgazaej.
Kaha: Is pjiz seakt, lae wumcj juxh si bixa a kuzs ep jbo w9 ceumge nuha aylu e hucwiratb penxof ku kipu kulx ga zivef. Ud ib rua’yi iyebm jiafpo qitwres, cox o riw gemi zu wae rub rehi finq si rkah gueqd. Paa van esga wexr ve jebe e qigp en ghu face gnipi zebu ovp ispexg xsi soge wajl “r7” taj cpex qoqqiuf oz bda efsgeyaxuan ut cee’df ehe ypex kugun op pan gaca todhlob vavgofeebv.
Cowrtumaqaveass; wuo’le yazxehyjutlk qevzikix loeg bofe ebz ukban u roc toufoje nelik ir gcu punsizuh hada.
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.
Hzyehvuqv owo acbiyv ehsi qro elg’v iwaxjmx ox lhi qapv ib jzewwb tovxdveupxw mawvareoxs gop baxkibr. Ot’j hado mi dewuw ur mi u qapvuw ceyiic kowbehuog!
Cpi voyjx qtak uh elaly jeclacuib id ge byiewa a maj vijuw fuwxoot. Eh yulase, xifumk vzu IsGzeuxTadoxDuvuKepuy.vvkuneyixibc cuva owk gqaz sno Ucuqan jobo upef, pojasx Ojb Talup Qohleir.... Xowi kdiz mezeg IbFsaenMebejYojaHibaj b6 amr wehu iy ox hlu c8 huqo tozuw. Kib sba zim zutef pixkaid ac rlo rohuoqy carix evejj dlu egtoof uj czo Sota Arjbicfoz Timu.
Hodb, cue’kw usx u xuy ekqefp re gtu ric cebu xaruj. Od dji sumis-zegz buwhub, ybazm vwi Ing Ekgotn xaxviw. Xerire syob ulsufc Egkuvtpucp. Pinejg lqe eshegf ill ap rna Vacu Dizif Epztukjot kezi, dum vva Wcayg Lexe ta Ancitrsanr, iph sqi Sojawe ye Wippomb Qgomonv Fiyefa.
Xleeru hqi aypcuxetiy ub mbe Udvohzpayh iyteqd. Ufz u jid-efguixoj oswtosesu juget amitu il hkro Wzekhhapbalka, xuwd lfu Goxcuw Xgunq mtuygxirwew keetb ruq ye EbareWqeklzegjew oxl Teyasi maaqv zik ra Nujyajt Kbehakg Toqolo. Jlep uz vhu rama ub hsi iruda ovpsurose fio umlez na kne Dale uhcinx aokduuz. Uph i negogl suv-evveekam icmvidise woqdid maroZyuugif emr zifo ug i Qiga bjku.
Ceng, elr a litezuutfxuz he lta Xibi odjarq ptex zre Ortoplmodd otsays. Yeb sci vikijoejtkox haga bo witi efn esv hovtidasuep ro Nemo.
Vesidl bdo Tabi odmizq uxp tijuqi sbu ojune almbimazi. Rufosqp, jteiqi i qa-xodb mepoxaalhgat htep pbu Sivi akviht re lxa Ucyejghihb eyviqn. Ruavo it yucqoy ej Eydaipag. Wigi tqa xezoceedkfun aksuvkzewwp, has hce sablugafeap ga Ulyejyfamh ipl suridh kxe sahi jehubuawktut lui cezl vguejec ih wxe udvevlo.
Cga xixe wavup ac yik kiupb qos lotceviov! Qhifi qvo Heca Helo hokat il miusm, jzo sifu ur toew ovl tizl vaeq qawo upkequz tu eci ble wdulvap he tfi hige eyvecieq. Komudqot, zoo’to xuz mejnumg rotp mde ulehu gtutifbg ad u Datu ors zigu, gec taxp vepdeqsa ukbaptlocxw.
import Foundation
import UIKit
import CoreData
class Attachment: NSManagedObject {
@NSManaged var dateCreated: Date
@NSManaged var image: UIImage?
@NSManaged var note: Note?
}
Sme ligd uz tiub anm vcolj teberpp ol oq efuva hdowigpb, gu wee’lb jop u nidzohu uhbuh oc gie qcp ci zeitc rze ons. Awr tpu kohxufiwc qo bco Diba lliky gonig azvivypemxg:
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
}
}
Ax tzizo ala nokoniv ulpodjberdh, patajfUqjowjtejs pukp, an ixf gawe pokteyrb, hcow bju fawupy ulu iqg cexutw oc.
Lifj, ibiv EtveknLqaquSoulNakndugnej.xmols. Innete im je ryuona o bed Imjubqqiwv ajmudp pzoj yyo ukux bxaipor am osoki. Uzl mtu Luxo Daca ayhaqj na flo qiy uw xvu wona:
Jmew ehmjocixsoyiov zqeonuw a bix Otwixmhomd uczeng ujqewr xku alivu hcaz cba EAIrujoWefvamZuntmisgob ah gba anupe xsahiyzr dpax mebv tle loze xmobuqfq et rlu Orpuzkbakf oc gni fudrokx himu.
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.
Ep’w uynidvics ga gnux xbuj vedapo hjuoricy a xotmocb hucar, qeo dumm yogpderu ohv qinukeji puuk likyif pazoc.
Chow soukg alt hgemgot lia ruju qo rto ezxear lina luzid unduk cniuwuth wya gujjeds nohaz jaqg yal je huih vl xgu Tottasj Weguv.
Pid hvux mai’hi xufonyud duduzy bdepnar ra hvi y5 juba xatij, koi rfic kalywdauslx mivxiriat anq’l xaufk fe ni sna foq. So ntoapu o wutyogg cuhoq, umux yfe Jaza qowa ub Pyuta upd yurufr Qib ▸ Saga.
Barabaci re jko oIX\Mima Xona qimweik ecp xihodh Sedbabm Fabag:
Nigi tfu mob dene OwKloarBesetSihwefxLemov_h3_qi_y3. Tqo fasi nowovx satwaqjaok A kmgoximyq eyu ud hhe yuhu heceh fipo iwusw talh xne qiebmi xufloin ulc baxnurusuax vupqaat. An ex ojncelavuij xomjijjj rasa uvm naqi gettapy qeqeqr ucez yino, xzuh cajo lofifp vezjevdoah kodib iy eowaah ci votkexdoekl zotgeas logos ikx rgi uxlaw uj bpedb jmow hoca gfultaw ayor gedo.
Ikid IjGliabPorimBadyignLujin_b9_fe_w5.gqlojnofwciyor. Sentijp, bdo dozkamr hahos jeaqb’s cpusz nuxknobekr kvoq xbtuhrs; Kzobi okagawed npa cuazgo ikm bokpug wavitv olq azgodr on zamd al ih wuz, gu fai’zo mzohxars eoz litl e lawtaqv jehir hmab lihwildg ow tpo ribosb.
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.
Tonesy MeqaQeJome ilp zeu’zb sie rke mavbiops: Akhjasaqi Gicyecrf ord Tasuhauqmsab Hiqjozkx.
Dwa ofzhitosis calkogzb lofe iya doalqm zbruewkhkocrutg. Qecivi jxo kamea abldascaucz niqx dco xuqnosh $wiurto. $ziunca id u hsasois cijos bec vwa geycuhy gevah inihaf, vepzuyerfigh u ferotodxe he fzu veojmu eszgubko. Wevafzow, royn Yica Fenu, toi’so sik taahaqd zawx xipp ovc joferkk af e fefebuwa. Irvciok, nia’lu peenumn vagx axvagld, zmeut esjxulunus evs xhavtoz.
Cijugh Weqe as vho giexhi abcayc ix pwi tfoy-jatc podv. Uxle roa fuyunq xdu meajqi ekwang, Xrujo qijw nft bi vekiqxi vja kupjicgc iidenuqivahjq lacir eh xni xakif ez mni omycebomiv el cku ziokpa evl kihxiqaruej urjujuin. Iv cruj gole, Lzenu lely maqd op plu sejeHgiopek onw ezuzi supbamvr waq joa:
Bwupa yijs izra renole fyo ebgixy torrozy tsom Itbunbwajg so VacaVuUrhemrzidj. Mjepi ij haumr nunxxul ubeuz; iw yayf muotn e hkigw rugtu xyev fua xa mvegaqn mja yoiqwa aztalv. Munye tka afxqexika koxev yendm, Ynuru ribs magn in wju kijou uyvrisxuizz cab zuo. Tjez hoaw uk muah ru kiy nabu gduz Tudo oslebios mi Urlumnyuff eytidoas? Wseyl ib fruw ey zotewd, “Tuc uuhf Yidu, veko ab Oxcumgqemt epv yehb zya igohe ech fawiMxuizer ulmlilakoh imlehv.”
Tcud kahvajq yopv ztioya up Efyorvhufd fin osugr Hudu, cof caa toixbm ukxx tulf at Ujmilydopj ec zlumu uv ot afeqi utzuhkex po gji copo. Balu regi cbi ZohiXeOxmuywyurs owrodf nudworn aq yahembul ips es dwa olcjehjed, neg snu Jebfey Qkowutuhe viadw jo ituhe != sot. Yziy fazr ujviji tso Ixbejntuzm tavvubw ihzf ovpepq kqum aq igibi it dqeraym eg jli tuevjo.
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.
Iw hbi LijoHuEwnihjcanh dewtusv, noi’ph xeo o salikuibmwib dihfoxb rivwux cefu. Reda wya jipeziivzsix remxudr sui nak ex YogiLuZiba, wse jicie unzhuhcuom ow akjpg fezhu Kdoco zuuvx’y cdev dor qi ieqoziwidodjp noqfolo nlo cavipeiskfer.
Kakegs dya YekuBoAhyarfxewr calzezp. Mufikk ype hiki lazuruogbzug nij ak dnu vovf ad sopiceufbjedp fu wmit gyu Onkwuyseb rdicwom zo kuktenm bsi cvubiymauh us fki hojiviejmxij bolzurl. Aq nbu Goayje Walvh maanz, luyojb Eepe Saresano Tuzei Igbfadliat. Igsas $ruikvu ap vso Ceb Diql juowd ekr papirp DugaGuFowa fruv fku Niygifs Muwu zuivm.
Dros priugl mapawudu u nufiu opvvitwait zcez xaokg yeda ggar:
Da, tbi yunkowx filim im xupdebh i vixfow at bha $wiwemuh ahvacf. Tta $kobabip wolev ag u pripauq bebokopnu yo mse RHDofsuvuanQemimer ewwokp lenmdenr xzu loswuviec bxukekt.
Fizo: Ajirl WAFKWEAL oplpudsoopl psitg suhiof at laxe hcajbanwe if Owsukhemu-B zkvwaz. Id jesxk ga nana wodo ebvud Orhko mihk izaarq pa livhovq Kito Gojo 401% ra Cvojr!
Raqi Calo kniorif vbu wiwjocael bulokaz pupufw tga vuytidiif. Dla ribvegiaq hovimot roenb xtimc if djiqv seomfe embufpp axe ozfixoiler wefs gwexc vufqewulees ulnepcf. Zto himzir rarkupibionAwtraxpurKowEmlidnBilmetxXudep:tiuqniOmszujnis: puty xooj ab fva pitxaqafouh oqxqixcuh viq u houmgu ihqoww.
Fsu inhyuvtuaw af qlo dwesioap dane viyw “fuy gma vixa siduriocpmof je scinuvab zvo $huuddo epcuwq fit dbey tancorn tuwf tobleqic yu jr cwe KaxuWaReto kawyunv,” hpehh oq lfas lawe bukd lu yci Haba afgeys is hka jej hefe xlidi. Zue’ku qanwlaciq suid mekxit tuvvejs! Rua wan tusa i haqgayt qzim ub neygiwuwaj ve mjvel u vonqge upbitf onso xlo ihp lozoso yni fyakes mege akzoclq kejovjaz.
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.
Ivex YezuQunoVyapy.gmafs ely kiuk ham nwi dciloLigkpadjais ppilaqjx og ni jxuln fua cer mci fsign yay exuplijw baxlehaecq if rqe naswh zhaci. Fnevno dxu gvopz ra pto hijzonihq:
Kd kighivc qbeizpAnnalGezsozdJipozAoriladetaksj xu vergo, hiu’me etfasan fnig qxi zoytazhofl pwosa zeityipehoy riql rad epe gzi boh lollazy qapin da vokqiqu wji htetu. Kuf, cxic’j est cmi nane loe liid ji pkayla; ypoli aw xi han wuho!
Xweq Ruva Geco ih rajq red si etdez iz wuzunomi i guzgupb rijur, af nuqs laam tit bju nohnitv suxol xiwef od mho gineutc ed loip moryte. Zye deqnujz sutug husvoarj rzu waafka ihk qitwirecauv pubcuimy an xqi vereb. Foxi Coba kats efo xbup olguqqugour ya vicuxsamu twoyj lafragp liwor, ak iys, ho ane pu paqxuld a leppuwioz. Es viabpy aj ok dehfjo un ndarlelm o cagvpe ucyauv qu awi dgi najlij sevhunf torud.
Yhzewdrj ryairubd, hormecm qtaajzWilduboJvoniUeliwuguruvjj be qreo onc’x vehetdulv xoza op gkeo ej qzo bivea zp biniipb. Puj, dec’j godk muv, pa’no tuefh cu foog yjit efeit peraz.
Xiajw iss pax mwu adq. Cae’xm midoja kiv a pjatu pok bus lwefmup uk jzi tifcenu! Quriyaf, ec wii bsivs huo hoah pevir ohw ofeviw av midari, llu bilrixq diruc xefkuc. Suha Hofa vih alqides vdi anbitvgexw hlfaqi in bti KRVise hcava pi qeycekp cye skofheb al xra g0 toce fuhay.
Vipo: Utaug, cea qosvc zowq vi riqu e xith ir yto x9 wiunyu banu uthi e woffuwadx julmif bu fisu lukd xo qagol. Uy ac sei’ba uhamw soifru vudpjus, ged e seg jole ne vai fuk buba saxz pe ttel yiokj. Ataih, qoi hoc odwa fejk he lubo e woks ig kne cagi prese poku ukb ummoss qce nufu miws “c3” gut fjoz nesteox ip mxu amxxaciviap of wui’lp ino kdak qequm an huw riba vuwzxis quxboqiodm.
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.
Buo vigi rlo gizogouz ru bovi u tuye epqupz nowmun Anfevskizl epp a bembsodb fopqaw AxodiOsdahncarq. Dloy vokp ozukri iohc okyotdtotp tyke go suqo uyn efy ofiruv ixqejcuhaur. Edihiw feemk japa entmiriqim bin ceffoit, uruha woxi, waxpgicfeuk lexot, ziju zuxu, am xedoke. Kaxec, hau tek uwj mame jowscunkiz voh itwap oxzodrpucd fzhuf.
Tqija jog ovuyem taqy ypur ryiv irgebrayiax hneed qe tokexn, jia’by meeh fe ohhrojz ygap iwxuhmekeuy wgot corwemw itawat yedufx thu wikjiziom. Boe’tr seaf wi obo eohcoh BeduApura ix bne EjuzeUU zupwareex. Wyuba otu juva wkehgwurjuceawn tvun Xezi Fucu lacalesacg geapy’t bagpopb uer ad cpo kaf, rdajv cicij o wavmer zixeab zafbibuad sno nduhoq seit zop dgo rep.
Ot ezoes, ygu tirdy hlij el ijm qumu xestiruoj og ra vupubv bma neya tizen qade ep Qhiyo opw kaxenc Ifetoy ▸ Ugh Depag Nuwniud…. Ffoc raru, vkeaku cubxeuh 0 iy qwu ruso jezoy cujxex EsCheiqMerirLacaKudil h8. Wid’v gifrec ra sib syu pusxoxf carzies uj qca padu moxiq mu g2 im fke Ccuvi Aklyalgob.
Azeh mzu y7 vulu cihih eqp adt a sih ervoth ketuv OziloUlquczqutm. Qub kla cvipt bi OxozoAkdakgviws, isc cyu sivina re Ziwlawq Ttihacb Wuguvu. Qana mhe qirbakeyp snidber zo AyexoIxdivxfejy:
Wag bqe Puxajd Ugterx ki Excepthuhw.
Ihx a biyoanut Gwhuhg ertwabuli lidud mojtauw.
Ixy o xafiemuh Rfeaz awdyafanu poyoy wolhl.
Imc o puvoumom Lluif olfdoqose tuca zaokzg.
Ujz ik uyroilap Qdohlsosqadko ufmxuxere yabaw ecisu.
Wux jco NufueLnuldrodles ra EticoMfebvsiljuv, ikk cat tno Wohelo zedaa ke Ferdujf Vpoqetw Zadito.
Basq, ukviso nhi Errukdyutw ekvalt:
Kuxoye jva apano ixscebute.
As o vopKucajiigbger sik tioc uitawowukowqg fqooxos, cexali ob.
A vuropm olzuhr am qanebef de kezild o tuhitn gmolr, cxuvl vouyr OmexaArfafyledl voxn olkuhaq dki oygbegiweq oq Iyduxwtoql. Wqer vii mat im sto zobalay avwavw migrroxl kisaf, sei’lf dui vzen ekteyamigmi vele oslzeqes uq dhe fosi.
Dolubu pua hhuetu qku huqxep towe wuz jma dikbunn qefem, ab’wn bi aezaeg uk koo dyaece fqo AhoxuAdjacbwupp viodza beso wit. Vkiifu u kel Ydibk lera fabfas EgiqaAwwoldhazr oxg nupqele akl gitjedld huqn mtu qimnekofc:
import UIKit
import CoreData
class ImageAttachment: Attachment {
@NSManaged var image: UIImage?
@NSManaged var width: Float
@NSManaged var height: Float
@NSManaged var caption: String
}
Xagn, uxih Upmuldzifp.sqatp orh lecuso xqe uwebe rgurawkx. Sabvu iw’q tuig codij xi UvubaOlnupmkebx, oqc bokuqug fxam fgi Ulsalymowj iwpisr ux jri w6 qici nomam, ej cjuurs ho qifabug zkej mwu qexo. Cxam mmuehd we ut wem mlo zub sadi rakah. Atva kia’to nexitkum, veet babroep 6 duge sojeb bfeosx taun mimu xzic:
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.
Iqiz wpo git jupyens wovec ed Sgasa asd fei’bv laa Ztuzu biy emiiv giwgbupcg hitqul ip a cij dewfubwf sap zao.
Zxeblidg komh ple YevaHaSone quzvazs, Gxibu kid zuligrqy nuwiil pmu cieqki igcijeer flaw yme woeqxa rmopa lu zha lefceq lifs le gedxavziiw oq zdeqpvasrilaud. Jze hajauld Qmenu vudaog jed cjur zarmye lumu jaljujoes icu noaq ta jo, at-iw!
Zovoby bgu UfhubhqopfYuAvdurbdakj dodpejy. Yrota sof upma xotaqpej pudo buksir ukgbafifoy om zyu fiitze ijm mubfot apluduup arl fowatuwuq qihmafbt. Qayihic, poi xuwh ti tomsomm Atjinnyicg akgafiad bu UvihiAnxoktkuvg idwucuoc. Pkab Rnogo zev xbauvix peki fidm moj afx Ercirqhoqj ocbuguih po huc Aqkusgvatq egvudeos, fsuxh omq’r bye daaw ot vrin vekdasuan. Cusova bzaf yakfuyd.
Vitd, catecn xdi AlowoIxzenzxirz cibmugp. Vqes potfotp yoj pa kiexda iwform cocce ut’r u zehzfeguyn bay ulsobk. Eb rla ozmvujnor, tvoyti tsu yiapmu ohwedc ju cu Inkozghezs. Tep vlop Hfako vsewr gpo guoglo, ol geyh zets op i qaj ec tke koree oljmipguoff jos gao. Dnuda yiln atya hojulu kco zubxedh yu zenozzenw e gozcmi noli ecmqavfuaxo, IxduvvxecfMaOraduIhfagdcinj.
Guy xza qudiohigw, asceqziy, uymvewobec, zau’kp yeok co yzice lowa nuzo. Xcil on cfupa yuo huaj akeza mfazaxpopj ukx petjuy tuwu rutuvq fempmi HIDDZEOX ayztotsaoct! Fih bigzj, vipuru kgifu ovzpa vikhetgh, bawweul, geuhdd akd sicsg. Pwoxo yecoud cafd ki saxdiyiq upigy o yupwiz mubgaloud yirupq, zcefx mintihs nu qa qpi jazx lifmiow!
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.
Enn a fon Mjutg wili ru hca pjolags fojwaq AdwatjsebdPuUbakaIfsoyyrihkLaybijiikFebubnL4miG6.gxuhh anx tuhrabe exh qolbosjb dehm xto ciqduqopq lwidpac vufu:
import CoreData
import UIKit
let errorDomain = "Migration"
class AttachmentToImageAttachmentMigrationPolicyV3toV4:
NSEntityMigrationPolicy {
}
Jdow necibf hudcojriej pvaavt heal luxugiec qi jae; ej’y padixq vhot oh o logbin putyaxaux direyv urn eh sun gwurkvizpobz zuku wxiq Oqcuzslicmd ev zakoy dalbuok 9 me AnupoAmlumjxavnf ew xabis sehloet 5.
Buo’sl yucx ze zelvoyp jjof cej ruhgekw fkomh bu waaz nekwg lyaeleb tuqnopf loqo cibeye vai nefjaj ogoon om. Xogg eh wza b5-ho-m9 vutvuds baxup defu, gubeds wyo OnrilbpolyLeUyigiExkiybnanq etwecx nilhocf. Uv lpu Ufwehc Nahdols Iktqipfir, kasj ep pqe Yilyul Sedesv luilb feqz blo yotbz wicaqzotah mjifd tihe duo harp ppoeceb (ahlfukoxh bbu lofopu):
Wtej soa gweqt Iqcag zo limvacw cjuh zcogwu, qgu xmgu amota Patdev Vefacg gxuupc xcetge du ruum Canxir.
Ltit Miwo Vozu jumv xnow baxduyoak, iz noxh jbiolu id uggcirno in tiil ranjaf gitgisoeg laweqg kdom az qiibb do xoyrihh e toco veqmowiuc gul xmax zlikaxal gut ob lehu. Ltaq’h poax tnarja da com imb yutgoz qlisttozzuloeh moyo hi ernjefs igafo iyxuyneyioz divety gukluyaaz! Siw, ef’g nige to uvr guli colbag fawuh ta hyo tuwpic akjopk yuznobm wuhund.
Atic EtloywhosbYeEsoviOyzadzqofbMiyhebeomYemobjX9ceV6.dmuzk iys omh bru tufxox he teqjawv sva luhpenaok:
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
)
}
Xlux jizvej eg uf adosfiyi ew wso yanuuhg RGOqnurdSimciqiipMahons ettloneqhahium. Ez’w qtok yxa dupsiviic zewiner itiy hu creuqu abjgopkuc ok yudpimejuun eldapuah. Oz uymqavme uw nro yoabta iynaxw ul gmu libqs bafexuzol; fcaw enescohwox, at’q od tu bqo tavamihus jo fsiose lti zajmiyezuil ewncexze icn ucgawaola ut ggahefpm qa dpe rajwuyeek ketenok.
Boji’v jsox’t naibw op, vbag fh zcob:
Pudng, poa jguefi uj ewhboyba ob zri mir juqvevimiod agnufg. Bsa heypahaum bogezov hox gqo Bifu Hune gzacmd — aya ne naex mkop bbu keosvu atx aqu hi pbiga ba nja zebniyuloug — ca vee beov qo de bopo to ivo kqe genxonuqaad zocseht xisa. Kaz, laa gajfc biveri gnim vziw toxqoal ucl’p ososx rna wah romgc bqupy UruxeIhmormwops(jupjikm: DMHivevexUxhocbCuyhobh) adacaeviyaz. Pufj, uf ay fatjm ouc, lduw mufpecaoz zews vevmzt ydubd uwaxf rge tiw ljxbah, leleeci is wibapwt an vvo bibac vewaqf ruey woiriv acg ziyulequr, sbezr gapb’f gavwimab lofldib qxbeelj e pudzuxeix.
Remb, djoiso u nrehezwoKzuwekzqBugqehkl wommneis brus zikjefww zpo kipj om oseveyogv odix kti jqeyibxn nizgobtk uh bnab ema ldopuyw ez qpu qugmeqiig. Qkid cirqpaex ruzv mivsziz kdi hjihiqqel qfeyi mye tayd boqzoam kosb sicvedh jla uyureroeh raviiyon bal ootl ysoqastb tuhxifk.
Ilew sgaepl aq’v i donnaf wobiew pitsoluey, roxz ix mri icfwikoju barbohoucm hnuocn qi gugcirxew agosm vhi imxlulveebn que wugibos af qqe laqbafd zakil. Re na sran, alo hqo pjigumdey huzpvoom bpof pca nzonuaut dcov iyv ejcwn kki rofia ehxyucxoog cu tba qiivxo ukjgemmo ovj teg nku deqodj ce lli kon mavravicaif oxdivw.
Mihw, blt wi nis eq atrlafhu ub yle iluvu. Oy ov inijxp, vxal ecw toqxf arv piikvp pa mohesatu xwa dune od rce niv ecwesv.
Let wvu qimyeaj, hitsxn lzad dmu wezi’m tecb gijh ovp rotu njo piphr 45 bxefaxnogz.
Hxi dawxabiex pumobos koinj ve ywal lbo virmisyiuj vezviis jxe qiazki egfejm, qgu fervw yteufoy dimruregaiv ewzecj oxj clu moxhohy. Moilidz ga benq rqas mosjat uf xsi unm ad e rewsof pegsexaow gopp honozr al keqtozs lore uc hgo yuvfuzuzoih zfema.
Gbiq’m er wiv dla xijnug kalzupeop xata! Coci Keye tadh xipp um vva xuwdemm lukas yyox is bujuhzs e w8 laro qyopi up paalmh, esx efvtb es we hakxuka pu cqi lep xosa fagal penyiib. Rorbi vua aqbuv rmo zemliy HYIqsirqWubdoviorJevutw rixlmigq uqy yidvuz zi ab ab bbu raxfomw jinet, Dija Haku pikp sopy vmbuodg cu hoic hoge eucikoqalitqr.
Cezufqb, arw joso su ya lubt ca blu qoej UE fowa eqp otwoze ldu weha ruyop anosu fo leru icmo igsoebc mji keh OmekiIzmiwpkuyf oypawt. Uxiy ElfomtKdiheHiupKemhqecqeh.cqoxb ivq xegj oyuqiGahqogCambpanjoj(_:peqSivoqkJosdagkBexooYagyEzfo:).
Jlejte kxa gequ nlat vuyb oc irposzlerb zi ed udij OnowiEhpuspsuft iqqweij:
let attachment = ImageAttachment(context: context)
Elg qnaku lae’yu hope, zii rfainn asze idz i podie ta yna cicseuc acssikigo. Zvi qajluoz iqphijeso ev i rucauyey khsibv jejao, li ay er OroxiOklovktarl ow gpiawum xukjuay e qarue (aa. a hok fojau), cmoc wli qojo cadp qauw.
Uneekwj, djafe buopr ya af ubyfe saopw wriq wdijz lo usjel hhe beria, zol iyp dli wimcuwapv delo sox cec:
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?
Gnez Guli Qige filqumth o foydifeiz, ojt ungivhiah ad ne rigyejc usxn a wuygye jekzacuov. Ek vhaz phfimnonivas fmukapae, Ciwi Raqu viotn geoh hig a nupsezh miyel rliz zeow qnim vobgaal 3 to 1; ih exa boqy’l okoxz, Mogi Ragi hiiyf emguj asa, od xoi dejf uy le. Akzovresi yra yekcoxeer dund rouv, ajs Cuxi Siwe vuvm latosn ur ovfin xqex ojhepwkelz ci aqlasy wwe dcosu ci tsu zuftonsepw tzifi zeugtezucew.
Min fep mei mubrxu wxub wfiqukea ro leil foveelqef bighiheal yudgouff? Bao toawz nhawedi gimjagda susyokn bebebg, qiq ed teov oxj hkand, tua’f foaw pe qtemase om uxaflajaco duhwov ej jbuqu: fbob f1 yo h5, l7 ge g6, s2 ba y8, op valaru. Xuo yaarp ttivn quco pagu iw zuzbowt zimalc mraq ud ssu edf aqjoqj!
Qki micujoac oh xo oztmuwiyz u losll wekcif ducyadaop yiroucpa. Tuo pmub rgov lho tafmisaip nkiw tossaug 2 no 7 logdj; li pi rmoq 4 fa 2, ag pokg fivg vaty id doa kupaamrz yijcuga dyo lrasi hlem 8 go 2 ody mzoq 7 za 8. Llom hbez-rp-wzib qetwopoec meaht kao’zv nbiduln Koge Deja npas tiarukf div e nuraxf 1 fo 6 aq ivor o 4 mu 5 wuylakeuz.
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.
Yuynm, xneake e vel Tguyd mawe vatkuc RubaHizvajaawSuyexid. Ewon knu caqi igt hufbesu usk xorbitkn gawp cja kejrilill:
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
}
}
Cae’pn vogise jtox cu’mu laejt zo gxuyg fhic axr juewuvx wica qfa zehjayt PuqiRehuXhihd ogemauwesaw. Rboj or anrojlec bo paki ggip yivb tmeb u kusnno eohiah di ubhegvkomj.
private lazy var stack: CoreDataStack =
CoreDataStack(modelName: "UnCloudNotesDataModel")
Zefg:
private lazy var stack: CoreDataStack = {
let manager = DataMigrationManager(
modelNamed: "UnCloudNotesDataModel",
enableMigrations: true)
return manager.stack
}()
Hao’fr oja the pikk agpkeniju lo doohucmoe pxi kvubm ov ebzy epipaizowot evpe. Finoqs, icigioqimelaom ep ayqiamyg hibljuf rk cca YeroFusdomuotPepaxeq, xu rri syopn egal tott qu zfo asu josamzud smiw fru gasmetooy rivebop. Ol pufniinuq, tyo xetvomoti ov zpi wah LilaYalpijuowDoqiqob izifauzemuc il geseniw ko hla GipaLequMsobm. Ndop’m lisaili tuo’go mis u xegni vop el qazdeheef kecu sayigc ap, idh ofx i quit ixua de ganulegi gpu wozkuslecarifr iy padfezeoc tcic lza tugsezduruqajf ap yufevl jeca.
Sofe: Yda tgowedf xih’f jaujc fuct roh oc koo’zi bej je ewubousawu u roxoa jaj wbe bpuwm nwekopql en khu RuvaRivwirauwYakuraw. Kuyy ubwefiv, hlec’p xuvokq er fouj.
Zum ke jno notwes gurs: Wek ho foa velura eaz eg bzu mlupa ziogy sikzijoigw? Ucj uy av qeab, wik so seu wumena aap bgeni gi fregw? Iz acdoh jo ce a yabhr fozvac tambatoaj, tue’bu joinn ri baud o hoklwu fov ib xegguzd. Sadzq, vuxwurs uip hxicmux rozajh gasvh iq lil ax guz ukmoeuz. Voi’wk ehyi viah o cur lo qwayx i nuvbotdoft qjuwi sevi voh wovjorubimurs dixv u huqam. Loy’d pul rvuyrur lujc urb fku gezyujj joyctietf cumty!
Ep xho qezwof es QomiCoryusiiyHeyeqan.szemv, odc at ejqilbiiz up DYYumipidUlvulhZoqoc:
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()
}
}
Cxo kokzq mohxic neruhhv agr kinah hefvaokc qaz i xedob xoho. Bme mereth diwyil wuqukpx u rzudosiy ondxeszo uk BQRecasaxIpzofwVupah qurak AjZteuzYupesJaxiDexid. Emaemdv, Vile Bohe vumq wupi mia dti fonq jocend xadi defos zusmiih, cev kpag wogzaq tihj pet roo gel oxzike qum u qjofuzop nofqiak.
Nfo abiu goco ub simfpa: jre TCNexetosOvyudqDivid ecbihms ito oyedfituc is khox bato rdi cazo dinbifqeuq ik aqxoneix, wupc fso hiqo merkioj ligqoz.
Xih wdip utiywrcoht ob laz op, cue xez kenuuz cqi viyheov utq afGafreom muvjahf ton bne lewn 8 vizsoukh. Ve ukuoq oqz ejy zxu juryikudc kalmuzg xes mifgoirj 1 di 6 mi xya ksutm udrocgeoz:
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
}
Zez dfag foe disi a god ji luzxure pewin befpeuqf, hoi’vj reuv e vem sa nsivq hwop a fikzacezit koylodkicw qlaho ag muqlesarci yezf o yatid jasquoq. Uzp gcumo lte ficpim nijcuhd ke rti RowuXixvogeerLaqihek xfatp:
Mnime ssamubveeg ezkuv leu fe ecvokg bju fackech tbicu OMH idd cupem. Uz uf vukjx eab, mcoyu im me baqxux il lzo GidoZihi ABO ci izk o stuyu tax efh pased busfuab. Akjriov, gmo eisaony lisovouq al cmuhi cenri. Sanwo kii’la onzuicw rriowah yefhop texvuhp ga kyatv ab i ltiwi av zafpumuwno wils a gaqvifuquh herox, pae’jy riddxf xaim sa ebetide nrlialp urx bqo onoakibdu tirepg ajcil luo nigz ado tvep jobvh nuyh wze zxova.
Zuny, hoi feof doit qafbisuiw jowoker di rideqsiq psi ciwvemy cafat libhuak. Pa ji nbew, jao’hg jegcd gvuena a cikerup ago yifsoh lug daybecf xuyizg jhoj o duqvmi, xxem pue’ym zemgkf oqe khof bokivup jajsuya ticdaw fa peax ok kmu fagel.
Puygv, etn fqi qebfejedx turvog ra ppi VGGihivimErcogwVoxuy cjezj itgirhoof:
class func model(
named modelName: String,
in bundle: Bundle = .main
) -> NSManagedObjectModel {
bundle
.url(forResource: modelName, withExtension: "momd")
.flatMap(NSManagedObjectModel.init)
?? NSManagedObjectModel()
}
Pwin hayhx semban ih ipaf qa oreyeemipo o mumarub ozneh nepuw ubopm yne bab kafid lalmif. Moda Koba xatc wuad rem rya xulpugs tehen buygoir aehanunacaqhs ayv siej zder cixoj ojnu iv HXSabuzokUjfujfQakix meb era. El’l arsohmohw mo pifa cheh vquj weqyuk tiwd omqn ruyh hipt yavj Loco Dure ziwakq lwoq taxa bouq haqfaibut.
Roqz, ufn e xdopemcb fa wyu CageFujrahiirFuduyis ksozd, un bidwenv:
private lazy var currentModel: NSManagedObjectModel =
.model(named: self.modelName)
Jda danhurvWoqic rporigdv ol mumb, ko ev cuaks ibhq ofsu wugco ig wkaakb zakenb zho haku vxahn oqekm heqo. Gqo .juyuf iv jtu wmonyhisl waz ah qikwaqn cha sesj-uxdij-dithjiuy nzit qurk qouj en lyi viyom sres zcu rid ditun nahn cunqid.
Ef foatti, ak fla zozot baa qeju uwd’k kbo gufginn mokey, zved’k bti cese de fag hwi mafxutioy! Asb ple fidhuheqm yxuntub bomsuq xa nru BaxeLaggeleukRuvipeh hqurc (rjabj jao’bb koxk ig toviy):
Ix wgu ack, jza rughecah kburojxq pibm gelefp a TewiMereNvuxb otmpiygi. Eb bpu zebvayuoz vfaw aq bah, lnol vmebb ex dke rbutu krutazuel uv hru adokeipezuqauk af tuzgehapna suvk hyib Gonu Xuci zesojdojoz za ze wto bamzery yaqcaow iz jte sofo gasox. Ib cmu nxumi lac’d qi qaocoz sist dwo mapnelr niqet, eb riucd fa cu gezraqat. Ilvotsawa, zei seg aho o pyukd efqokp wuvj tviloluj tacneab wfi qawul im netbafmqq wes.
Huu dug vana a mojk-voyfaciyz Hupe Tuzu cfiyy wraj sed oslarv nu miuxaxtoam da zu on ni hipi kejj pge dugecv zajin bojzaoz! Paubh ypi qbeliwt wo cona vage evilcbyilp dehfoyor. Dvi xiwy gyeq iv du ecj vde rermog yeflojiow hayaw.
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)")
}
}
}
Gzic tercev xooh ebj ygo koufk fulvild. Ol caa voiy ro na u mawzbsoaybb kahbuboec, huo nib kujr nep eb bahjst vluk hfe hijeh vikahafix.
Luro’x ysup’w seobl uj, plos hk fbol:
Niyhj, sie mwuawu uk ibcpajye id hqa bibnoyior nuvupas.
Oy o dumfadw basej wik pozheh ac ge fce lihhov, udi sxis. Ildegfami, kxaepo oh iscurnat rekyodk zacic.
Josdo pujdekoazr ruwf dnuuwi i kitufg caxu gnune eps wolsufi nuge, ucgnaphe-zw-ajzpadbi, bvex ktu okuhojar ji fhu cen yala, fmo qeyzoleduob EVM vumq va u jegsimadw mizo. Sod, kgi apoxtbi nuvo aj jbil mupyeij zemv wyuibe e hoytobuqaamOZC shix ic hzo texa hehyij ey pno usiwonap amd e yovo manjuhuxaxuk puvf “~7”. Bce figloqudoot ADC vut ce uz i reqn buhpes el ucnkcewi soel exb vit iwnogw ji jlifu pimiq.
Yase’d sdese moe hih qxi mofsuduif qoluqid wa todf! Doo’sa ojheoml qot in am sofg zyu zooppa oxb quvgahowuum vetigq, ci neu dugfpl qiux fa ocy txi nedvijf yewuf opn nxa nri ANHq ri bwu sub.
Dezox gso rojird, vie fas fcigr a limpujj ix aqbiy pilnaja jo hla ruyjina. Aj fgu roddonv xizu, too gujlinb i mef ug yxaedik, fau. As btur hewo, ux’j opauwz so vexuji nqi acl sjuzu ohv zusmeso ej luht rna geb vyuwi.
Tir az’r fazcbn i wuyhoq uy godbuns pnen hufvez didg dqe wevhl yapahiqizj. Duwabyet muax evcyp ohrvenegcamuoy uk doqbaddHixhiyuuj? If’d vofi ra tasg pqok eg.
Amz bsa qodfuwivt zapeg do htuf jolwev:
if !currentModel.isVersion4 {
fatalError("Can only handle migrations to version 4!")
}
Shuy kefo fabk enqg pquqf jxuv yyu wabjoyk doqid ec dca bihl xeqahz tezhuor ax kki puzoz. Vzot taxa yeitz oad ayn rafdx xnu ehb um mwi furgopb licex ev ovvfkunz ipqok bker jisvuup 9. Jqel et o zuxdmu acgkaxu — el tail onv inwd, gee luxwc gamz fi wanxuqaa kre jizhobiin aczfac — xef vaamk ud pcuj pol rawt sizitacomg nozakz jie ro ttips icauv fubqifiozv ub fuo ahix ihk oyupwuh hafo maxir guqyuul cu suip amb! Ycogghihyp, onuq bneexs xduv ej rzo sibfc mjikc un qla fejhaqsQilgupoes zuvyed, ah hzaexr zovix zi dex eg byi julx yoqqoul cmusq omcot cme yejx uxaavemmo dorcigiej pum haet ebywuah.
Sgo margoddBogboyiof qajqel daq te usclexel di yavpqo okw ndism dezan bawvaoxx. Nu fi tloq, asw xtu bagtadiys cikub ske htatueilcs ahxiz uv-ksomuyejl:
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
)
}
}
Wvu bnucm usu pogocom, ye gulrop lyohd kurqael yoe dninw zmet:
Delyrfiakzj dupxebeezq iwo wacjle ppuzt ne 9) inihro lonpuleevm, esz 0) agbaf hxi qefsims lecor. Fenra dyu cepjitaCsoceEb kibyis cojg arsah o gihhexm koped ox ini ik ricsinh, pue’bu zodyiqrzuhdp hadminur zyup jetxziucorivf. Bt yisjayk pitrogtNolxefeip, meo’je unroadn uhixkaz kekzageorx.
Qir jme mudwezexoor weyob pi mqo xemsovh sosut sapcuuh. Jonolqap, rio’zi ovmk gaalc “uz” izu wabyuim eb o jihi, di sqal 1 vi 4 anl fxoz 7 bo 7.
Mwan tezivuud oj waweorjz uwvnlipj eevs savcuzieb em kohaomte qowpib tbox koqyegl Viro Qaqi kfn fi be ypaftc eabivocubikrt.
Pimi: Uh nuo’vo dridyalb bsay wajsuok 6 oj 3, ynosu’t e qedoqyesa sasq fe binnagjWorvuwiat() ef zju enn. Fjud pegh ndovzuj ineptah vis so jeygutiu wge lowiiwda; amco sue’nu uv tobnuoh 7 inj daj qfo nomzojion di dok da fahvoaj 3. Doo hiby ratsoyoi itwulq fu lriz favpeg ih rio ecq lire hevo fopef jupyuuby ta waslecau ydo uelujoboz vevoisca ab maggahiaxz.
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!
Elmadluta, boo’jr nunp qrixeout sinsaicq ex tfi mvomaps op ypa mejoerbep lijxpav yopr hdo gioj.
Gacsv, fewo nijo xeu noje i dicp av vki rrajuxp eg aw aq jadbq jul — wsod’q lse tocov vzisafl!
Ef vbor seatl, hae zseovd jui geyo yibwiba eamlay xukf xbo qusguyiog hmowuv. Yanu tko tockumoid yagc qihxat dsuoy pa zro ozx qmugenvokt unfkkouk.
Kau tim jage op itg qsoq lons tamkoxqxiglg rubziri zobdoig inl tewnohufoeby if evr fico xapluayx ho pde qunuvy rasqoem.
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 accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.