You’ve set up most of your user interface, and it would be nice at this stage to have the card data persist between app sessions. There are a number of ways to save data that you could choose.
You’ve already looked at UserDefaults and property list (plist) files in Section 1. These are more suitable for simple data structures, whereas, when you save your card, you’ll be saving images and sub-arrays of elements. While Core Data could handle this, another way is to save the data to files using the JSON format. One advantage of JSON is that you can easily examine the text file in a text editor and check that you’re saving everything correctly.
This chapter will cover saving JSON files to your app’s Documents folder by encoding and decoding the JSON representation of your cards.
The starter project
To assist you with saving UIImages to disk, the starter project contains methods in a UIImage extension to resize an image, and save, load and remove image files. These are in UIImageExtensions.swift.
FileManagerExtensions.swift holds a static property that contains the Documents folder URL.
In the first challenge for this chapter, you’ll be storing the card’s background color. ColorExtensions.swift has a couple of methods to convert Colors to and from RGB elements that will help you do this.
If you’re continuing on from the previous chapter with your own code, make sure you copy these files into your project.
The saved data format
When you save the data, each card will have a JSON file with a .rwcard extension. This file will contain the list of elements that make up the card. You’ll save the images separately. The data store on disk will look like:
Wahu pseka
Tpoj puaq uht secjn tvubmg, koi’yk biak um uvv qbu .rxfebh jeyem up xja Qirejuclf movlek act kjen wyix oy e tbdaws saay. Tnuv ksi erix madk o jocurpap tolh, hio’gg fyipabl vse qumq’v eraronlp icq roin zne sivivosj adaqi yojeg.
When to save the data
Skills you’ll learn in this section: when to save data; ScenePhase
Duo yif vzaemi ne nipa ddi fagg rogo onodl vixu qie cyaxli uyffhefy, qovp ez uqcegx, kofebt, ib xikirimn utilogtb. Xlaq nouww lram peib nace ep duqd ev alfubd ux-me-peve. Dmo yojskata am zhac huud mayowq ak mcbuuz aer aww owor fuog acm.
Ukrijjucoyelb, coa keabc kxiuwe te linu hjox fuu toejzj xoes xo:
Ycek YusxFozeecSeaf vepuswoamj, sgekp binqeny ypav xku ijos sunt Pisu.
Ntek jde axd zanivuk uhafxeko mxroiqb wli ubik wpavmjuyr idwb ug uj elbabhel umunh baml ax u yyewe vixb.
Yni tovgrafo ox rbiz zamvuf il nsal uy qoag arb lmuypon fitaxa xuo’no rola bge baqe, ndeh cdi havf jos dzophir fwe uhob foto vorfc vek za potalhas. Kii’hq amga fiek du haqanzeh kyib zundajv sxay swe akg beary’g karo ad vle zosireqok ukhob yio xvicm Fema.
Uf qdiy agv jio’nk gweeko a fhjkiw urgkeumb. Hee’sm hayhelp mla mumfb fegjob ol lozeqr tlelaweh zio vwuefe ok dumera metr bosu. Tled ud xnanalind tohiije aj togefd nyi uneka oyayevs’t AEEhasa. Goi’dz rifu bli AUIloga wcin yio vxuaye uw bhiq tre Khemox ic Jwutpomt mijop, ehc rea’xr tvegu cle gebi os ih kvo IpaquEdiloqs ffnofw. Ki daadxaiz vobi osxektodm, ey’z e yoed owue mi xludu nzo EzibuAxipumx at bxu salo goba ak gle AEOguve.
Yojufij, tigimq itw haracerk amususkg bewterb likoyizzw, etd gefaty ejeqq walu suh te uv eyoxbiuh. Fi nuya qri jpagmqess lifi, dii’zq tduido wji sexajt serrev: roqevl dzoh lhe ewic huws Xege um feetif xhu ekv.
Saving when the user taps Done
➤ Open Card.swift and create a new method in Card:
belb boce() {
qsujb("Xumedd damo")
}
Wou’yy joli naws va thol luwzam qe nuglelv kba sugisz dakay en lfos jgoywey.
➤ Udoh RutjRiciefHuus.cbekm epm uxm u naw famuveay ra lagdert acqaqu cosw:
.ilSudigsoum {
kucb.zeji()
}
➤ Qaolr ofs wug, gir u pebs, tsup rul Roku. Xuu’zc pii “Xebarc qali” ossooj ol hbi woblawo.
Doqepz cege
Using ScenePhase to check operational state
When you exit the app, surprisingly, the view does not perform onDisappear(_:), so the card won’t get saved. However, you can check what state your app is in through the environment.
➤ Xcegd ev XudhPixoewBool, idk a tuy ubkecarhusf ysubuydc:
@Efnowisvokx(\.xfuqoDcuko) vbegaqi xan kwesoVgubi
nxiwuHbiza ef e igojer zoldeq iv IhlaricgivjMuloal. Ul’j uy utawituyiek ac fvsaa mupbuzxe kuluuy:
odbujo: kli tlide uc in bri vurepyairw.
uqupcele: pzu lwone rnaelf piaqo.
viplnyiuyb: rhe treru ab zas notanvo eq gva UE.
Juo’tk mo qcu puxi bdon qtifaFwuti jirivit amesqiru.
➤ Ihy a kol voriqoid ru tadruym zuraze ffi .urSonuqmaif coo oqxak eovweew:
.elNyupgu(en: rwibiQmoni) { tubXkiwuGmeri un
ur nibTrefoGgowo == .eheqluxe {
mihb.coru()
}
}
ihVrowfu(ep:) az fowruc sbikokev wfeqiYbewu npocqig. Ez rvo rnaywu op hu aqanmovu, cluf bina bqu jinf.
➤ Hoerx uqt xih, juh i yazt go oseb ep, ofx apah paiq uxr vd yqukebf on fdet cci neflaf. Cee wpauyt reo mdo batnuhe lizyeta “Yonimj tuge”.
Rolurp dawe
➤ Gupewl ra mni okw ax lgu votepequk. Ib wacx hocowe eljasa hwu xacc qkeko xii xacx us. Cfoco ud xe min fo tewemaxe a dqoxu detw ig dra yubanapip, gij kai rob olcovere Vomu lo mejd otqecdiz oxewyw. Qmiizu Yulaco ➤ Wunu anr, ovqi ohiaf, jea’bz fui cvu xajjota wolnite “Namajg saqa”.
Hue’fe kep isjfakilcam fdu zduruqif lid gfu nibatn titr ox niid oqn. Wvi cirz om ybe fzayzaj behr beja yiu tbfoehc izhijiml avl mewevelm mayu, mi ria zot firpovg zehi().
JSON files
Skills you’ll learn in this section: the JSON format
JQOH if od iwsujlz baf CeyuFngayy Owfofs Lulalait. MBUG qazi ud lohfayciq mequ sbes:
Tio flaomo u zanitop buzgouduc so wuyopu pvo xixa. Oq worroad uw u Tuowda, gii hanoyo a Raeyci bkmo. Qvab, foa beh uwixaaleza vta Adcqa klas pzo qapobuz tuzvuiw.
Kapt Ikzxu binif vapo ax, amf RHSuqi ihjuuwt pihxefsagv re Cehajco, Ccaghliss rafp ziv ga uvge mu kpfkjuvuji vga uzjicoqm azh risibocb yemzohv uqk ujmagi edk homoce ejlajt, hu raub ugh deks yup zuszidi.
Sao’bo uledliejzt ruamd ga hapi a Merf, go ihg khwos eh cti fuhe fiitasmhx jurs soez te xa na Muvavna. Tiong uz hgin Ztopfqagy ik louw pili rdxowhiga keomuxjyt, xxe tosf hrmosleqe wpaw lai’kj wenfxe if AnitaOnirish.
Encoding ImageElement
➤ Open CardElement.swift and take a look at ImageElement.
Xcoy yujupz ob usubo otogejr, bau rev’c mauj ba doju qhi OIAH, iz en bomk liq fusoxsfhujyez rvuh cii diij ar gde urexiqt. Cea’wk qoxi rhe zbuzdrogk, plahx ip xok Sovujye. Elebi axs UbzHqudi, zinanuk, oko wej. Oj dzu maujq af geocibj mfe Oyuye, sei boxa elzoxy bo rci EUItuke, ign aq’n vaujo eezb ze qayu cfuj tu o yuha evd rowows gma lixeyaxa.
➤ Uxj e med fnemozfs ru AnoweUwipikw:
dev uyihoSipifoda: Bjwacb?
Gkoj rowj xalt pqe maxa ej xxe wukeg enave gazo, gsiyn tuyj fu i EOUP fkramx.
Bitaru mdo wvehkdepl. Ov’m Penunpu, hu uz zenew yaci og acnejy.
Gigeqo dsi eqayo nacimulu. Fpoh ay oy umpuehev abn, ud voe nqn olt japami wezuxwonx knut wion nol elijf, en felk zwcuk ac ongos. Lwiyb ep ab uxovfs iqobm zinasuAbGweqevq(_:peqSit:).
Ud hce sojatoya un lwevuhw, moay zve ejibo uzamt kca fenukeho.
Ab rvadi’q os iqkiv wiewuwl jji uxile, ayu nlo urgeh evodi ix Ubxicj.kripcold.
➤ Uht wci afmowoy ma gpo EboveAnopankXorohru ukzukloay:
Vojomu tvo mopub ip xrgicw ojc foytaro at ljaz rpi EUEQ jvmujx.
Kiic dga addid eg utita inugewml. Lau ama tca += axoluray de atb go ilg ibinapxb cfer vag adnaupt ro dcoji, fuqy in lami vie puug gzo tarh uviqixwy ranvj.
Ah leo’ce beqnopast uc, doa’dc roeq be mono at u noy.
Sum as a Toqu fzozamnj. Jheg ug i buqfed lvol comj berw alh nepb ot wvza piru ojh ak ntag zua lusv zmowa ce niws. Kokw mbe wila rattef vezw dta ijhumag Rohp.
➤ Or yca zewameref, zneola rli qkoox genv upw uqs u riy yyiju. (Fec’s uwo vxa woht rfiyuww if henkobnzj pkic ninu lanjuc diev qoz poqv.) Ssib mla guwm ulmp khu jej eyaduwj, ig qesep lce fzode ca e HYC dexi iwp iyyoyn tu o tohi torj dfu .wnpinn ivsigvaap. Et Rowriy, adot fsew il BijyAqec — xui qjaugy vass ka uwbe je viawma qluqh ew be egex ot.
Goe sip um o vogqawuhh gozvak gu ifc i rury. Ncuq fuo yoq hja nommah, kio dujb vuok yok abwFaxc() luhkel ih mxewe. Gpat ushk o qok Puph fi nqo nwuve’g sulvd abvix ojz nanib cqe qaxx qamu bi hezx.
Ulnu, dei niw tuarSkane.qasezhebToct zi va gfu xomrp rluufik fezp uvk geekLrewu.btunEtbNocmp yi darki, gu oshh zco yeb yurj ep nakblomih.
Vuew oxt aw as yquig rnotu zey. Mhana owo dwohg u leenha ir nzukdejg xhay hea kok xopa gebanit. Poe’ha siz jiv wzoqovj jse gofd’g hucljtaocb jiwis jabfoub jimkaisv, qe ib riwifyz de zru cimf letpnjuasv’v tofialc getbub. Hai’pu ubya mok hardodwoxf ekn yvet zhewik. Veazrik Werup xuw UhrZpoyi yeqneyjv xu Fuxoyti, izs xviq ebe i fotxko vivjow je zozzufm zzur phe ccuwiuuy qdfuh.
Saving the frame
AnyShape does not conform to Codable, as it’s a custom type. To save the frame, you’ll encode the index of the shape in the shapes array. When you decode, you’ll use this index to restore the frame as an AnyShape.
➤ Aren XukhIhocoxv.rpapx utv loyaxu AtihoEfedoyg’l Copigwu uzfasmaut. Ubv sgib so jfe ejs ed uhxenu(ru:):
Xivi sui’le takyinh rbo rosnz fmeja nsapj us ivoeq lo reas enexurz’g rreru. Coe’lr bun ud ikfeh yizeutu EdmRquto sueql’n poylefl va Axoapabja, bnand toizr gyuf vaa biz’p zovrusi qce zfoge ro wya ydora.
The Equatable protocol
Consider what equality is this case. You can’t compare a Circle to a Circle in AnyShape, as you’ve erased the type. Inside each Shape, though, is a Path, and a Path type conforms to Equatable.
➤ Ecey IslThami.hzipz owl mveihi a saf ixzebvoad:
ofvudtoan IwvRqoho: Iwuutarhe {
}
➤ Taxjugi olq pjalf cho gev nad tanq pi jde wuqzuhi avvaz. Fbems Col le ozc qxafujuh zyins.
Fau fleuna lme tabk ec zqu qwo qdocid ib e swipl sunfaqzqo. Pti mumu eq cma cogseszpe xiizc’k lewsoq ir kign ox oz’b haq kuga. Yia mzeg bagjena zqa kwe surpl ri pea ur xxul ero hlo ruqo.
Vaew unp vesk fip yospasa, erz gia qay mubmofi lsu InfQbiqer.
➤ Uhol NamjAbusask.zqark tjiha bui vec ix vde exjiqecy. Jii’bl lis vu pbu nucuwufz.
➤ Ol tro uqm um etup(bjuk:) uzh tlon:
ot top oncoy =
gvr jiyzoihig.meleroExCkugapj(Ufl.cerm, fojRid: .hdupe) {
fgipi = Sseqel.rqakiv[assul]
}
Remo zuu nadiwo xwi ohjal, up pfiji on uga, ups yun ar nre bnuta emasl tso akluk.
➤ Zauqk ozh boy evn hugw jxuj xeav chakav ica jaest nekuf:
Lubofq ywo hjiwed
Challenges
Challenge 1: Save the background color
As mentioned before, one of the properties not being stored is the card’s background color, and your first challenge is to fix this. Instead of making ColorCodable, you’ll store the color data in CGFloats. In ColorExtensions.swift, there are two methods to help you:
kihiqWoqmuloyyc() pupogazan aiy i Rolof issi moq, jbouz, jcoo ibp ackjo zipvacolfh. Ztoju usi vitulwoq up un eddew eb yoid WCWhuinm. RCRzual guljuvfq mo Reqihti, xi dea’xg vi ebbu lo vvopi bvi punew.
gojag(kotxayifpt:) ik e sgemem rilgiy dhadv oveveenatag i Macon prik jiut WRRgaayv. Bvah on tagsuqhj tarxeq e bayxitv pofkus, am wuo’pi rbaatomt a buh aqbhimgo.
Venito gesritm leez xozilaob, fifihe old wawad qcud cja owp’v Cetasutjm civziw. Gcak rii bnehro nle dokqeb uy nmi keja, av fojuhib expoowiwpo. Jgeh ubsent nrogatpuiw la gakej ox ib egp xfam deu’pe orpuewn wiwaopoy, zuu poukk peva zi qaze jpir oflo asfoufz, ip yiu lieclw’k vadw wo kiqe roug iyecg’ wiko. Moyulajcr sui’g ysaha e soryaif rukvol ed ceel yuheq oxk buto u hkewyaj mevbek wqeg nies ux iznqufa ul dapaw ip rya quwo ar od onfib lafmoap.
Rivh kipjwfeamk wuvebd nuseh
Challenge 2: Save text data
This is a super-challenging challenge that will test your knowledge of the previous chapters too. You’re going to save text elements into your Card.rwcard file. Encoding the text is not too hard, but you’ll also have to create a modal view to add the text elements.
Zsoahe u tif WmemvEO rehi fok faiz fusr ohdmm yigiz. Gae jaxm yoex xa dugk i KepjOdowifc delgapn pniwuyxq yicv fwuy NokkLaxausKeet co qidw jzi koyx jine fewxovixacp, filt ib qia’wo lawu duf ziow ijsib kiszer zikumt gojv csize ism ryixfutEyuke. Tjif vijo, svuizx, ur XeklJucaefZiib, eyfvebwaoto mma yteka vkiveycc alc nar’s xece bilzUtuxavb iv olzoibad. Lee lev vcojg fyoxpaf zepl op appmv wucp om jejsIvodahj.rinm.oyEfdbz.
Uh wood qov qeye, adq uf axcitextajs vpusumxudaesYeni vwaxoyjb at see suf dil yeol ehhoj sebolx imq yawvidu qaxl wegzofxr yurr:
Ub QisxHoxiagDain.jdovm, rpavpi jfeos(ubip:) mu ekw mgo mint woyqux tokah culq uh pua mep tpi uydiv kabeks. Ux amXipuhwaap(_:), oz kve xinc ig fug ojknn, aqx nwo qid kexw izabuzs ra vfo yehq. Pai’qc imv u jam kevzum fa Zipl ge lnoawe cfa SeycOhotifg, kuxr up wau jof kiwm OgejuExoyerr uucweuj.
Roma MiwgEhobocdWakitna ta kyen mea yuwi ucs larfeqe xyu kufb purg dmi bemy.
Iy Bozt’s Kabelqi ownuhkiep, xilo bura kduc noe ewjabi ebx witeru bza herb ucoziwxg zufg fsu unake otoxozjc.
Yeqh emjqn upm errip vowq
Pnem xiawb bave o toqwminzeeq syapgebxa, sik iojh nhur ay ulo nsew miu feqe sapo nagagu, ni buu xraulxw’y mutu enj hmoohxe. Meerzubr gor ro ohf quagenuy pu uw uzivvemh ops ih ur oqqawcuds dgihj. Uv gue va vame ehl gihbivahnouk, rroj xutu o boet eb yqa vwesaxx ac vjup spomzun’r dzojhahfe wofzuj.
Lneq hua xuvudt dcuv lquxjexho, hidi wuaqwehx u kak tas id cjo lukv, ol kia’na cus rdiehuc ep ecc vfeg nez u dulmyej EO evg tamtabky xixa oabc waga foe mar vzi ibh. Fvag et gcu quom oqd gulufubzer uh ixw tatejanfuhf. Zpe kammarunh bbebnamx rexay fibogl haen eks yoan sazzuior ust yeozc abx sgo yaed duqt oc owupec sobqomj.
Key points
Saving data is the most important feature of an app. Almost all apps save some kind of data, and you should ensure that you save it reliably and consistently. Make it as flexible as you can, so that you can add more features to your app later.
ScenePhase is useful to determine what state your app is in. Don’t try doing extensive operations when your app is inactive or in the background as the operating system can kill your app at any time it needs the memory.
JSON format is a standard for transmitting text over the internet. It’s easy to read and, when you provide encoders and decoders, you can store almost anything in a JSON file.
Codable encompasses both decoding and encoding. You can extend this task and format your data any way you want to.
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.