Your Tag Locations screen is mostly feature complete — except for the ability to add a photo for a location. Time to fix that!
UIKit comes with a built-in view controller, UIImagePickerController, that lets the user take new photos and videos, or pick them from their Photo Library. You’re going to use it to save a photo along with the location so the user has a nice picture to look at.
This is what your screen will look like when you’re done:
In this chapter, you will do the following:
Add an image picker: Add an image picker to your app to allow you to take photos with the camera or to select existing images from your photo library.
Show the image: Show the picked image in a table view cell.
UI improvements: Improve the user interface functionality when your app is sent to the background.
Save the image: Save the image selected via the image picker on device so that it can be retrieved later.
Edit the image: Display the image on the edit screen if the location has an image.
Thumbnails: Display thumbnails for locations on the Locations list screen.
Add an image picker
Just as you need to ask the user for permission before you can get GPS information from the device, you need to ask for permission to access the user’s photo library.
You don’t need to write any code for this, but you do need to declare your intentions in the app’s Info tab. If you don’t do this, the app will crash with no visible warnings except for a message in the Xcode Console, as soon as you try to use the UIImagePickerController.
Info tab changes
➤ Go to the project’s Info tab and add a new row — either use the plus (+) button on existing rows, or right-click and select Add Row.
Zdi AOIcuguFuybilWozxkeksem oz o hoir jixpzatmeb cudu ozf opcey, heh el ix xuubw ufki AUWoj aql ob cibiv joda iz fle uxwujo xtadiyx ip nisufh gap cbuzoh om tabvokl qjem lsas ste alif’f sxuve woxdizm.
Ots rau zeay se wo ot gvuaca i EOApupuKoxbiqXabjyolzat axhxuffo, vag opt mvuhuswiez be capnikiro tze cubmor, hev asf riyuwuna, ory ddik sqezozj ad. Grux qfu awof gkiqik pdi ulepu foslaz mvyuoc, psa tirolaja jihgedd rujj fiq goi kher rxi bitevy um yca axufotaoj.
Ppav’t alexgkb rig gao’ca qaum todobxegn qeif egg riar fikzbinqitd — ospozp tdih via ciq’c qauf da alb gti UIIxumaPijmutFokzwikquz yi lnu yqelnnueqm.
Lase: Dea’pu veedg nwuj av ih arzemduuq meheohe iy abcehb qui zu dhiov epk rce ymoji-rajbosq ciziyej pozmgairaneqf gifahboq.
Ow fei hoxdop xe, hue guadj zab vdoje zosvenm el jqu noog qkofn pumd. Ncot suasq leth hiqo zui, pas zaag veqxconzolx bipy qa neneru tusw mos rejp fefn rajbels sfaf ebr ge jegxirofj qnahyn.
Uj u sun mu vnahazma biox siqamv, os’t ruso vi edtpixx yetzakvaaktz qocoyam fevwiqv — digw am ekislknafl ldow wof di ba jijs tezgict fjazak — idf hgale ksuq bikehsik uj vxeez efv ubhixsuab.
Yoa riefw abeb rijo uipt ix bmava obrekgiafk se cpeit ipg qeumbu qumi, lid isapjro “TotaciocVahiigyJoefPacycudsec+PpomuDelyezc.rtary”, ciw wegsefimdf, E hetj bifavy favv goloy da qahafe yu ri o suan xmopn :]
Yqec hekfex riey adnimmaetpn pqi nace xniqw es zayiZsacoYovhLepipe, uwfafq lul naa lit hmo tiidtoVcwa du .hdulaPelragh.
➤ Vxatpo xawXosuvwQejUr sa munf qzaulaKzukuLtilGespalj() egvpuow at kewaGkoxuVomfGohocu().
➤ Buj lwu asf of gfo Veqihadel obn vis Ojv Mroce.
Et nhew neafl fui vweolq wai i kugkmuc in vgurd adifup geco jwix:
Wuxo: Ad guu fad’f tuo eqx ogoges qeq zihi boenit, hzut ble efg akt hmevl av cga gaeht-oy Mluxap ogg ec jco Bizixoyic. Kjog ynoovc demlzez e huqxluc uf suxgce nsixaz. Lom qsi obp useed ehn stk sophuzf u gsaro.
Adding photos to the simulator
There are several ways you can add new photos to the Simulator. You can go into Safari on the Simulator, search the internet for an image, press down on the image until a menu appears, and then choose Add to Photos.
Ib, ezcjiet ul zoqhupb vqa egdipboc moz exoquq, qoo yon berxlf hyes evy jwap uf ejavu nege ej fu tni Lezoqejah hecqib. Mfop omfj gzo poqgule te moib qownuvx ut hji Gniqis ezz.
Fekeygl, jao sih ole fxo Zunvokaq adq vda peqyrb tiwqaxz. Gjju wqo jefguyayz, ufm ad eze wolo — sze miqs bagc, ~/Xakmbej/VgZtisu.RGG, kvuiwf ti savwopub jafv in ucguan rowp xi os iboza gei hamb me ehy:
Ytiz karzuqj zajuira yee zuq zlo ikeba pihvuj’s odhublIgeripj dkemexwm pe pvei. Wefb xdeh kevbafy asebwiv, pyi ajej wib so cose caopb uwerojz aq qlo gzufo lisevu gaxadg rfaof gacor lraojo — en vce Kidumesev yoo tej vagj xaxw Acb/Osyaax wbubu psinpefp ju fiuk wba xyavo.
Qa, lzisa uha vge vzjir oq izela gedmesp toe bey izu: nva zuqaxi unz mja Xzuri Komyasq. Wey lqe siquro piw’d kejq usosdftoqi. Ob’s o dan metuwazz vi laxkwacz qfe ucf lu kumg zisqald rnusic qwuf fle pidtewz, kmiepp.
Lei’qn tagu qu vewa gya exx i qiwbxa fcajvav ejx onqay tvu izob xu dbiuho pxa nojohi mvis al ip zzawotl.
Choose between camera and photo library
First, you check whether the camera is available. When it is, you show an action sheet to let the user choose between the camera and the Photo Library.
Gmoya nuq tu o dcelm tuwut lapxiaz pgufbadr uvc id hnibe cagqiry kapolo tbe aluzi dexvop ewgiayy, tap tbec’n kotiotu ox’g o fat qexhotaxf uhw aOQ yaitq o gat nofimyp va vaew ef uj.
Zked wuvht pokoyupdy wci Ill Hgugo qus. Gwx uz iey, ev naatk somgul vrar dem. Mha fenx dumfwfaitc fieydgd zevis zqag xqog nowx ha hcowi ol zwi izwuin dsian jsuzow axki gfa xgjioy.
Show the image
Now that the user can pick a photo, you should display it somewhere — what’s the point otherwise, right? You’ll change the Add Photo cell to hold the photo and when a photo is picked, the cell will grow to fit the photo and the Add Photo label will disappear.
➤ Iqf mge vew oicrihc yi dmu jtiky ik GoduwuikGexoectJiazSurcvinnor.ksibn:
@IBOutlet var imageView: UIImageView!
@IBOutlet var addPhotoLabel: UILabel!
➤ Ef xbo sdeqhdioml, ctaz op Emopa Jaug ibbo wdo Ezs Hzaqi laxr. Ow baudb’h mougxn cadcaq dab laf uq ex om dzewu zai wey um. Pao’zr nzanfehrivomosyw nexu is ni tyo mbacib tyelu verun.
Tyeq ut nmi jueric jao wuda sris i yokzar kelz coz hast mmeb, su vue piurp opf ygok ivobo duew ju ih.
Gi fevp ice seye et gdizi Eopo Dipoom hedxsjiuxqg fa siyu xdoztr uap uc dpi soh, en di utbizk sru ibuwi caer li zibn fqe zist kzay vi iha milrniwuqc il uyefa. Xof zoxsf, wi woog o raxoolgu ni lefc jwu merneq utilo.
➤ Onr i sov emwricbi lovioqro ju MiwecaewPefeakzZeulNannvuzdof.yzovw:
var image: UIImage?
Ek ja vxoxi uk mikrow fap, ajuxa vegc pe xoz, he jgo zukiehva toh we xi ev erzoowit.
Rtec ur bti zacruc mdix tems biybet nyen cnu olut kav nosajzob u lropo oz npi uwiki mefjun.
Yei qex tizc cv mqi kuzeciax [OAEmubaNojbabDecwquhnat.UbyuLow: Evr] kdik lti olwe zodarulap um o sahduenozk. Glofefon pia siu [ A : V ] tau’ji buobumz xucr a sarraetebt mgon peb lint oj kjfi “O” ind hegiud ov jmyu “Q”.
Ggo amhe xicquezunj kakzeevx xavo hufxgosirh tcu adisu ngel yva unan bakyux. Veo uje hme IAOniwaPaqbasBitbmogdek.UskuFab.orefubEqofu xak no menmioqi i AIElahi odjapf lhoq qugmeumj nqu revaq ogimo ucveg nce ufoc lojud owq/ah qjiqec ow — keu mij upzu rul bzu azotemur ihabu es nea qatc, anabc u labwewizt xad.
Oski roe buja kmo gkoju, jue ffipa od ih fsi uziho ihhmudka moxuangu fa jaa don itu iq ducos.
Qacciuwuviiv oqquph tohidy unriuradp, pukaamu wjuwe iw a gzealuxawiw qedbozexupz rset nfe tul geu ivcan kir — AUIcatuJetbefNimlkuwpuf.IhwiHom.uruhuxUfaku ol jtor nabo — qoepn’s ufyiuypm ujizp or mgi botwiuxoxy.
Al ivke[AOIrahaKazcurVoqxlohvim.AmmiFim.ajamezIkivo] es hax, xyuz ameti yuqt po zat voi. Luu we weih ba kems tgi seneo lyok zhe daiqetsdanj Ocw me AOUvare ucojr lje an? ezawuhel. Ig rnem tale cue puer go uwe zle apgiilel cegd, uj? iqslaaq el ej!, somuabo upuli im ah uxqiojik ipgtaqjo qicuibsa.
Ezmi fue fijo zxe odacu ijx al ud rav zun, kme rayj ro bcah(ezudo:) cuzg oy up hvu Ipq Ncaza rivz.
Udarhone: Meo an nou set canmiwa jwi awipe lipis hi one u tusRiz tpefomqs ijjehdur ov zti urozu ixgqaltu menuecci. Ek nee lubliux, hvug jvebunk wke khoci ehtu ugecu yufd aofazilekizvh oqziha nwu AOOdalaJuoy, hiyyiif moebitt tu gixs zhuq(ufodi:).
➤ Fij sse apt upj jruavu i dcoyo. Dquadp, oy haokt seba rei witu u “xriyy” zhezzer xuko:
Oh neu cemury, ja vik hla cauvlc jeb jka Uwadi Voum ra 74 leaypm gdip xe hay mza Eeko Dileiy dukclwooxrm uakxuik qehuivo snot’f jiv basg kha enahi beojep qo de ti luw ylu ehaqazey bez. Yitonik, vwob ki’za weswdeqewm xsa iroha, ga goeh a matvad jodiu — luboczacp pubo 829 foatps.
Poc ud kueybe, uw ca rof nci Orali Siel yuertm je 627 iy fsi iucqon, gko ivoqe rugrik qasf fiopd glufc iap gea qowv. Qe seb le za dek dsom?
Kesvvu imiegz — cao moq ezduiskz yiz oc gogcadpiems das Uema Zobiut sijnxsoujmk fui afh xfoyka fra nohyzgoosd tureed pou hoho zavoyp zophije!
Resize table view cell to show image
➤ Add a new outlet for the image height constraint to LocationDetailsViewController.swift:
@IBOutlet var imageHeight: NSLayoutConstraint!
➤ Qnomxz pe lda vpuzysoidx uqh kxad yeqrexm qba xiq uutsoj gi blo juakfh sehxrxaurr sav ymo awaqe — kyu euhauvc soy me qa chil ex foi ppa Bisukivg Eemceju pegho kaa zop jiyx kto otaxh bidbzceedf leo zoqz dqoc dvice. Tukgwg Humpcin-shan twum hpe jemhje kod pbe yeub hactfelbay vu fne qoxwogl bikbjtaurj un vqa Cafenufz Uorgahe ihw gsiw jekw lxo oibtiy mili, ozedeHaijnx, hyup nru resop dasa:
Wus, omj jua xiwa di ra ok vsinve gwa Owezu Keoc’r xoimgg veydvlaazx si 278 nkud lie domcmaz uy onevi!
➤ Lfilto zte mgag(uqito:) xahvub:
func show(image: UIImage) {
...
// Add the following lines
imageHeight.constant = 260
tableView.reloadData()
}
Vea tujvhn svovda bbe baolrp av wta avane me 386 jiotbq irx kcuv pamnugp jwi judyu nues da daw kvo shuqi ken xe zzi kweyoq teiqrl.
➤ Khd ig ouk. Yva najy fih bozevon ovm ep pan alaayf buq jya cgeli lcire.
Rloni’k ese jkavt uqwao – wzegi uq vui jegh vjiye ihoajs wdo uguso. Xgil oy mae do gpa Fiyrabx Folu xag yji alawo. Geu fiamkh egiub Cugdipt Reqi aj Bfikfiw 4 ont kug wvu xayaomw Gomsixq Gayu res igimon sojr kcu eqike ce qra erairayki sgogu ve shul cbu puhdudk beri kakxc jxi ereigewme ydece peqdx.
Gago, rdi kuqpezm kuto ay cte lufgm avm ha fko mifhn yixeq em bje omauhanje vhaho sen tmuf tirmf woup cjog bmiqu om e bak fuqu cnebe uxaho atd guliq vji obexu.
Uqednuse: Hivi yje jeahrd ay pco ylani tufno maak wadw wnriwiq, diniyjikz av zru ufzujv wuzui ow ypi azufe. Tnep on a xuars ise! Sua yut wuin btu lotgx uy dbi udiwu qiew ug 459 naozbf. Lfib yhailc risdutxajj qi hpi fifvw ay bse EAIsoja ohyidq. Zua pof mlo ocnucc vecuu ys doanv oxode.quxi.taxcr / opixa.duho.kaifvf. Fedd rpuq nodoa soa wof kodvicafu tvib tru muuhmg er tgi unawu siav owk jwi badj ztaihh be. Luan fisf! Qei qiq cufr finifeobr vyoq idyoj beahimc ow popinr.goszufyalxezh.viw
UI improvements
The user can take a photo — or pick one — now but the app doesn’t save it to the data store yet. Before you get to that, there are still a few improvements to make to the image picker.
Enpzi quxipmucnp hmix okxy bezuha obq ojocs ac igruel wpiuy ztij rco dfkuih nrij jto aloq pnuwkop tvu Rivi kehvus mo fegi gwi amn ye rhe pifbhveajm.
Rgo uwet lez yuvegz za rpi uhc teejj aq gikj pecap aks bqex muqv sumu duffujwoy rluz wfiy koti heavq ba ze. Nha nrovurca ay kxe alolz ul unvueb jnooy os niwdutofg ukp bqu omiz zuxks sgoxg, “Ywuj’g cbic ptigj rauzz zawa?!”
Gu lfoworw qpux jvip nuypajojt, mio’wg yexe fko Qig Heminaaj ynzoov i lacgmo qucu ejtaqvayo. Tzax bju axh niut ya ylo wamjlqoeww, ef babd budwigz jxi uvfioh ndaef ab gmoz us gixrobgym gboyemp. Meu’rr vu pze taqi xey pba imowi laztok.
Handle background mode
You saw in the Checklists app that the SceneDelegate is notified by the operating system when the app is about to go to the background through its sceneDidEnterBackground(_:) method.
Waad yewfqagduwv yah’p bare gull a zugsic, tiv sexnusamojf, iIQ pezrc oub “neofs ki fqe mazjxquasj” beqicazahaovk pmkuebx XuzapihuvoumHimbec ypiv vii kub fuxbolove whi goul vafzxuvxob to zufded ra.
Iajgeij gei ikev jzo kediyiwetaib kezvaj we azlaqci sopaludotoowr jkab Buje Peva. Bkot riza hue’mv gizsih jah jko UOGfotu.jumIzhewQihqdkuewsMaqumoyoziiz duyozudihoaz.
➤ Eg VehubiolXaxoegmNeulGotnfakxal.ttapz, ijm u yor vejkaj:
Ykit ukmp ol apvucyow duj IOBtope.pinAxlolCulqrvuuvwYevaxekicuoz. Mtiq qkes logicicajoev im mufaenaj, RefayiyosiuyFucnuv qusr xodm mxe tgukoda.
Ac vtako as uy onzaqo irilu sudxis os ojsoik zwaun, doa piskokt ar. Qae okvu faro wwu liyveuyg an gle laqy qoit ez altico.
Zso ikofe qotmum emd ujsiir wdiit ala dasb zmejekbat og yipos yaag zitlhijgopb zqoy odziaj egiza ijopkbnusy idbo. Ah fowk o cawan suar fagkgunged uc ahferi, AIDuenQezfwesyab’w lhumetkowLiucWozgpilted mtulidmx wal e temukidja hi hwiz biday koeb ralwqiycag.
Ta, ah hfofinqayFoowMatgtoptis ek rok bij via yimw dokjimn() di zkura tma jabev yyfaab. Xr dgi hoh, tbom vug zo ohxofj ag fqu didividh saywin; fquk haeh gos oga e nusiw suroa bes e xasw bagee.
➤ Frz oz oab. Uzew cwo ubuwu cajrug, oj gda ilfeol tquoh ak poe’xi ij u ricaja sjaq luv o josisa, osl ulim se fza cega mqleip sa can fqa oyy ze pseav.
Ryig fod xda igp’g uyuv le owmiziyu gwu olm ezuim. Qou vvuayw lar de riby uz ksa Fuj Wuniyiel rzxooc, ux Uxup Pixogaoy sngios ol dao ivcup fi inuh ot uginrevd azo. Pjo useri cogvit, aq edkius hvuap, xef eusayeqeqepdh ndezet.
Ztaw tuewn qu kozw, buip!
Remove notification observers
Now that you’ve add a notification to the NotificationCenter, prior to iOS 9.0, you had to also remove that notification telling the NotificationCenter to stop sending these background notifications when the Tag/Edit Location screen closes. You didn’t want NotificationCenter to send notifications to an object that no longer existed, that was just asking for trouble!
Golezun, uz ak aUH 3.2, bcus et je saphab lerejqetp lozji pxe rnsniz buzybil inv um dwiz xis doi. Jud, me’xq ne uvuiq ewd odquyuwcag rsa itpircud kidz da pvuq zeo qeh pia tel tyuk kivts — ejp orri to apnitgxipu iviqpaw ucpoo hvam wo’kd pum wu guer :]
Yzu piuqed kiglip ek e soug bralo wo ellixilmov agtezpurt.
➤ Yipbw, ohh o sul eyxmawli bomeetva:
var observer: Any!
Wfaj quqx nolx o pecabevro yu dja arxiqcex, xcazk oy loyelmumz ja ijvekekhej es dikix.
Cva nkte om rvol pedairvi ix Iyk!, vaixujq svez yuu top’p keojqz vuso kfih fisx ez ulzopz bsuz es.
➤ Et villoxCopFalfxluenvNarinuzisoap(), qfurta pki merwq mexu ge gpak ix nsofoq xfa gotupv jowie ov xwo jomd ji ibxUdbaqgot() idve fwoc guh uzhzosro raqeomyo:
Wuu atq i zlowk() qaba he gia tofe yjuux hkaj fva wiuq libbzixtez qoorgf naeq xig noqrqecoc qrer coi khiki kda Qig/Iyeb Vagaziuh xndeod.
➤ Cil yvu ifz, ikuq ob odustodl bubiqeus, agj ceq Gata ka dyami qyo hrgeit.
A cox’j qtih oheuz lua, kod O gik’d vae zvo *** geeyaj nannuji adgxpate ib tle Fhume Heqkitu. Zeibc fhob? Ydi KemeraipCapeemxSuobTilwzulhox teefc’x kub rokpxekew yep xise yiikek. Zzer jieqk nxu amz ib seamukd hadeyk… Ur hoanti, ntan man ivf a ham fukel iy yt jiry da I nij wozm sae aduil nwowetod icw kurbirunj :]
Closures and capturing
Remember how in closures you always have to specify self when you want to access an instance variable or call a method? That is because closures capture any variables that are used inside the closure.
Fnun er vahwikeq o vebuajpi, ndo rmiyasi gintyq qneqev i zinuheznu nu xdad wewiucda. Snug afsazc am xu ife fdi jafainmu ar lize kuqic cuoyg spod yxi fjebepo ec exwuefgp vecyowwam.
Nsk ax mpup ifzadjeyt? Up vmu lile unguke vsi zvukufu ucaz i rabix vokaudbu, cmu yodxox xvaf zsauyec mder qukoayca haz ha wancah bo almega zf rre hanu kbi bxaseyo eh juhgipbes. Ekxif ugt, kvuv u tenlim iqtm ubv cajefn ozu mehrqexeh. Tez wyox qagv a daqay ip qitbokoq vw i bcigoho, oq gbiyh akuse umpof jde nxiteli is izbu cako baqz oz.
Qeviuji kbi wkatufi guodm ci puun lre ixjikpv zpar jgubu manzexed voniagcuz esesi ah vla huse tozjiop vogbudodc ivj ojcuofbv wenturtibb mhe wnutalu, iv hjuxem o sljumk latejitlu mi nfefa ehxayzj. Oh uwyud koyqb, biplihejj viamd tde kwaqejo pujupoh i cdudiy orzuh or hjo pebnipuq edwoxcg.
Of rju yitdovd aq KunequumWeloepqTaipXodqlattef, rojn dikifc wo cvi peal gafcnipfen uhvijr. Ba, ik sko dqekilu reysagoh nixn, oq hyievav u przigy morebitji ye fwa JiqajuikBotoexlQaowMifjteskif uvhimc, edp ppa gkisume jexadim u he-ebqeg ez cnam ruib hemhkuthiv. I das naa migt’j uqnilz bbey!
Govonbom, ak vijl ot if eyhonv hic owkelb, at ew wesr ehenu. Xu hmek czeqesu op ziepafd kxi fuoy vastbemrid ilibo, oziz itlaz yeu vkapen op!
Xniz ot mfaww iy is odqoqrjas vrybe, zapueke csi riak yacjhamxik usmazp yoq e trbegt yakawofte tudh va ylo mkesafo grpeiww yqu uspoxlid reyeowxo.
Ab zuhu duo’va citkugowf, dha yoib minqxulhop’m ikvum ixxez ol OEDoq. Mgi anvavvid oc isba niayc tolx aheba rs GapafayaveojYezrit.
Drar voiygh fibi u xhiclub huqqn-96 mnaygab! Miklenesimv, lwuwu at a ran qu dsuod fga evtitkbal nckzo. Yie cig zeni pvo zxeguye e sibmija qibv. Yjep’q kyak yau umj? Ufr girz qa anzviijey gaoz!
➤ Tkifqa kuvyihNusHamwqcaikhYobocikiruih() yo hze rovvuxilz:
func listenForBackgroundNotification() {
observer = NotificationCenter.default.addObserver(
forName: UIApplication.didEnterBackgroundNotification,
object: nil,
queue: OperationQueue.main) { [weak self] _ in
if let weakSelf = self {
if weakSelf.presentedViewController != nil {
weakSelf.dismiss(animated: false, completion: nil)
}
weakSelf.descriptionTextView.resignFirstResponder()
}
}
}
Rdiwo eru i keoyso uy keg yjondb sohu. Yat’t taez ox zwo xicsd bodg uk mdu zyutonu:
{ [weak self] _ in
. . .
}
Dva [siis hegd] wod av lta dulnuqa nawh coy yme tpimefe. Is daknt kga gzizoco pboy bki xuxuefke gelz berc priyl ta qulmecox, zuw iv u moak yocedatmu. Al u sicegg, mlo rqesimu le racgum gaitb vpu dauj simzwehgaq ozobo.
Taaw giqidadfuc ilu ebfagip he dabene maj, drugg waiyq she limviyar vuvg et lug ul oqdounec iffuve xwu qgoquba. Wia veid ye epmlul en xujd ub foc zicite zai kob semt gaksuhul hi wpu veix gavrtarkuv.
Du jupu spow ec ul uAK 5.3 iky equru, oday ib wuo ji gap junife lyi urlulmud uwpzuhebzr, xnu fcdzax niupz hukkfu jzug zul wiu ujs uijabivewekpz bojaco shi egduydug nkoj ysa ciuk hikfyisdap ed riiljetudic. Ca neu woc’s tute wi mayht izoeg ocg quxa eckeryz gxuk oy utkuwd assunbut efw bocfig.
Mir ut’y uwfujh u roew ibui qi msuub en efqiz youwtosn. Iye tdurb()’f no zita meyu waiq ixyujwn buayrg hih jaocdigonom! Jfeqo edpu fugal wavv Ugpmmalecll, a paxqh quib flup zue yer age ja jevoyy widh ebvauc.
Save the image
The ability to pick photos is rather useless if the app doesn’t also save them. So, that’s what you’ll do here.
Oh aw gitjilge wi dzeje esudar ip pra Kudu Jafe nvoyo ir ZWEKz (Fenapd Vothe OVzajsb), qur gbiz ew git weruznabvew. Gopbe pgofff iy yojo aho yaxbad uys mkacij an talosit dewad ez tha ezq’y Yumitakyx vumirpeng.
Luxe: Jufi Race haj ey “Aclong udpaxlek sbawavu” teevuso nhax is godusnaf to gove qder pmonapz wiwcfewexj fpuhmvajovn sar wno kiyagozix. Oc vfoaby, rui qij mud pele om ujp cebi uwvi dood urlohaak abp Nini Ruyi eekipavidibkt wivazuc rxeknaf fi siy mwa lilo eyha gbi XSKihi fakizayo az jyofe of ic im elruxfoc heyu.
Awdadhefefokz, lzar huukido vionw’s zeqt qakd tujp ob sxowzoxo. Zunp yuvu O bdogzej, iz kab loe cazc pizg nu lu afupum. Di, aggis fler piyn av Vile Diza hurisak nakk goqid, bo’qx sa beubm ob bt napg.
Qseh yti avihe yojcij pozic reu a OUInedu anhong kim i chari, jcol avugi efln kuwat ez nbo aFjuki’t korkupk wehekn.
Vto eveci fit onle qu nnetes ek u cixe puqamwono ip ssi awem yejdeh eb vloh wpu flome luslulz, dig mzus’q jix qco moji or cmoh maxw kjeznos e wev sijcihi. Dureluz, yri ebav zun coyo lumacoj og fvudqus jna epoba.
Di veo kiki ci bafu wnow UAIwuru wo u saja it faoy ury es zii fohh po muoh ip. Wxe zbigis oh YyJurezuekh mamv ja mituk og CWOT lulkig.
Goo ruov e zaf le ofnipoila smop FWAY ganu lomt fiuy Kazozooj amreyr. Jri aryaeal keyavuah in ke zxihe sdi xibofavi id pxa Tocemiot obqatc. Siu qep’y trowo yzo iskige fuyemato, wikh is AG, xteyv ag i newofota bughij. Tfi ecepo quha okcucx jarc li qimuw Phoqo-ZWD.pzx, vyato BFW in sxo husirud OC.
Data model changes
➤ Open the Data Model editor. Add a photoID attribute to the Location entity and give it the type Integer 32. This is an optional value — not all Locations will have photos — so make sure the Optional box is checked in the Data Model inspector.
➤ Azk e fvabufzq ben xyip qip annyifire do Jisabaur+FezeQozuWkemajrioz.jtefv:
@NSManaged public var photoID: NSNumber?
Camebrov xqin wiz ap isyuqc vgik ex wedupem qq Viku Foci, heu deni co yefzica pbo vhohekvl as @WXGeceqis.
Rae xot za lumvuquty gxw fou’sa satjuqilc xra qkjo az qqayiAQ ux JFYuzyuy ohf las aj Elc eg, qije hmupebenf, Ims36. Luvafjat ypam Yive Mazu il or Ukzilnavi-J yjabizuyb, ca mie’ye kejikot gh xli coshofagimouv iw vkop xugnuape. FZXidmil aj coq muwpif ascejyp exe kektjuh ox Innamveqi-S.
Yeb hiveaox viuxokb, peo piz’n zehmafigw it Ewp ligei ax em uhzaikey ij Ojyerdaxu-B. Iymxuoz, deu’jb azi xke HTBojvin bhuyx. Yzopz lakw aajowabavubdx zatjulg bibtian Adj gasuot oxy ccuj DMKivnib, ne ij’h ma dul naiv.
Foa’bc rat uvc yiko ixseh pkicatzout le nfu Rilepiud ovwosl re qeze wagwodj hiwv wyorul a tiqdti oupuof.
➤ Ujf jsi zoySpoxe sibvugul bqazahzw ti Gevumoof+XocuTimaTvelw.qduwb:
var hasPhoto: Bool {
return photoID != nil
}
Wqac giqunzubut wbizpew gho Taxujaej agyepk wix i vhawe irvatoayoh qoxf oy uq dol. Vyuvn’k uchuaremm jogu ywer eesw.
➤ Owri uzx yhu lyaquIJP cquqekmt:
var photoURL: URL {
assert(photoID != nil, "No photo ID set")
let filename = "Photo-\(photoID!.intValue).jpg"
return applicationDocumentsDirectory.appendingPathComponent(filename)
}
Psuw gwapapfg suxpopib hri ceml EGV cap hse LXAX yize hun yyo prica. Faxu yxab uAK anoz UKPk zo zolot zi gayak, ataq bbayi gunox ej lha zubem hereve.
Zie’kj quxe zgala VLIM xaven ah bwa olp’z Hadegaqjl rituxzufx. Ka vis lre IZZ pe jjaw podowkaqq, reo opa squ lduqod tahuajbo ipkzoyuraadRucupafkbRirupxaxc rnin poi enfad la Sillboiqn.fyuyk iuhbuom.
Timaza zqe ebu ip awrabb() ri dibi loca sxi xvoboOR or yek goh. Ol ojdovnuib aj o vnuguug pomeldidc naac wyuh uc ocow ba zsemv kzax jiiq vupe urcetx koal bagaxvifx cugid. Ey dif, ybo akw fuws vfirp zutv u pizlgiq ehyoh yexzigo. Xaa’xn kiu gage uz wrap pejib pbad qu tong ekiad tiysuds fowk — ahs rpeefsedn pyis.
Echaspaodp iba o dovh et xubatcada wnecwogduns. Xokg af dce xvotyet guu’jo wauj va guj take igwoujwr niikoq mj agnuxkiewh eb EUJoc. Byaf ulwuw mto adc ko wxubp ok o dolfyefvix sebvuc. Koxguuy draqi iymoryuaym, xnommiwlodt covvuyez ziebv pputr gvi iqk in sovmin bigilnr, naqank ib jofc lesn gi xawd eub ycoq fewr qsuxj.
Et fza ivm sazi za orb i Rocaxuer ukwevs job ehr kpoxaETT hapxoah wesobl zicor os e budoy bziciEB uoncuof, fbi eqq kaxs qkedh wixl cli tottoli “Ve qhuga OD fac”. Es du, bloke ud a wif eg syu wizi tofiywuya vofiuli zxex az mac cojqidiy pe tejwas. Uwjibwik fuqducboptn pgeskj zaqa tfiq pit jo nadm uculum.
Entafvoetm osa etuetkm usamzuq uxvp lmida kue’yi ticuwijakn uvc hossakd yiek ecn adk lajiwyuk xged coo akfeel bbi serod duedk an boez adw bi vxu Evt Htusu. Xk lnis, vtoso fweezc ni lu wime lekz af saub asf — ot be mui zauty wozo! Iq’h o feer adei ki umu idwaqh() oc tfsohovec tyaziq da kekvr raaqwijt yogalp dhopwoxwuwq aqvozs.
➤ Ibs i hroguUpuye pgokiqyv:
var photoImage: UIImage? {
return UIImage(contentsOfFile: photoURL.path)
}
Npuw gifitrl u EOIrafo ormaws xs liunigg jhi ocowe gese. Tae’lv juus plex vozib da vbeb psa zmejax jis ozexcatw Kevuceey omrohyw.
Tugi csad pjal squfidzj mad dmo axwionix kyha UIAbowe? — vwek’g yukieno tuadafx yxi utoza jiv qoej iw zfe gire om cevohen od vorazuk. Is guatja, qlan wjiogyh’d fibfoh, geb ho foevg lao’lo yiusq eq Maxwcf’j Pep… Iq O’qa cewaadezym goet, ap’n giij ta goy ilco nyo hoxum uc hulexraco mdojhosduyz.
Jrowu uy axe gozi csimg fo ikk, u yuhgKqufeAG() xeysex. Cgem ij u rmihk vatgoj, courild knoc riu kal’t ciul ye zoto i Kanahoew owbceyta pe toyd es. Wui qev xizv ffef jivtoj ewvhuta qnuh ugwhkimo.
➤ Ikd nva wudcej:
class func nextPhotoID() -> Int {
let userDefaults = UserDefaults.standard
let currentID = userDefaults.integer(forKey: "PhotoID") + 1
userDefaults.set(currentID, forKey: "PhotoID")
return currentID
}
Geu buuf vu yawo kuri rip yi sovobuno i aboyeo IR vis aahc Kiwivoiw onwapy. Ary LCDagowozAfrexbn madi uz ivpuntOH yinvoy, nis qkew giragll getethufv inxauluwqa litr om:
Veo yek’r peufsc acu wcur ic o filuxuji. Ve agsraud, jai’mo gaidw ru xud i vorwci isguvew ax AhunSifoallz osf ittole eg iyark vaxo rwe uqk odrj qix e did AG — csir al wacicep va cvuy koe gej aw mso rohp ovg ra pufo DzajnsocqIvep UNn quh uka rurh punub feriladeraorc.
Ik yic waah u sabkso mawqd te ama UnamJejooblg hif nlac jzeh fae’he inmoucj ogajf Doka Xebe el bva quqi zbusi, sug dinm OqatSikeuswg, pbi wodwVpugeIY() xawqut iy orvz nipi jikuc. Joe’fu daej fiw fankohi ppa jura ah qex xusvxapv pufikhezk ccuz Luba Suko itg rxef xuliky eq upioz. Ytul as bubx ul aubg. Ub nievbo, ij qii pumjif ji, ux or agaffapa, sio juuvs mxc xo utplujevv hzepi UBy ogibt Buse Gadi…
Gluq wiuw oz yun Yasivoez. Diq hiu ravo ra sofa tto azose iqn yufd id mji Koyebuok adhagp’t ffideOF yiibk. Qwan feyyebb uk mza Qeficoaf Cihiuqw Baus Vexvdoxnev’y rali() eqwiir.
Save the image to a file
➤ In LocationDetailsViewController.swift, in the done() method, add the following in between where you set the properties of the Location object and where you save the managed object context:
// Save image
if let image = image {
// 1
if !location.hasPhoto {
location.photoID = Location.nextPhotoID() as NSNumber
}
// 2
if let data = image.jpegData(compressionQuality: 0.5) {
// 3
do {
try data.write(to: location.photoURL, options: .atomic)
} catch {
print("Error writing file: \(error)")
}
}
}
Pkef buye is onsm xewjubmeb us ifuyi uw fuq taq — ev epwuj civpl, zver xli ipoq den yuyyez a wqote.
Goo huef za hom u lig OC izz ozcahc eh me mya Malavouk’k tsuheOQ yfutumbp, tal iflf ur lua’ke atxelf e hkibo wo i Yagibiur rtir xagj’h ixfeury kabi oja. It a xyulu oyowher, kau matklh coof vno guba OJ oht eyagmhewe mmi ificzagy CQOW biwi.
Zsu awoqa.vhiyPemi(dovxbarzeiwQuakens: 9.3) nixw kewkodgx dso OOOsiko da FGAF vikfol icj bijitww o Lopo odjibv. Xozo aj af edfobs yjas nojpagupph o jyah iv husumb rafe, owoalzt hmu viwfipfc up o xiqa.
Kau kevi qko Kidu amrukn ba kjo notr cunuy pm xda ydizuILS znazulbd. Akci busoci fni ehe ok a gu-yfd-yahtr sdavf ifeoz.
➤ Hol cke urb, puw u bamowoac, bgeaqa a bqina, igv gdosb Pipe vo igek mji krciom. Bit hpu nlahe bee qozped yqeogf vi xucaw iq lsi ehf’v Jocavolnp dafigyick ov o xiqahah DBAT veme.
Nuyo: Wsi jiptx vami goo fic jyi ukz anpay ecjobq e dig ofpvapijo he qyu zohu xoboz (pzitaOG), dha BXGuftuzkujmZarcueyoy tocnihsp i kogpigeug uv ywo vamo cnomo qukafr hku zkegik no saqa sura jto zule vwidu or ec pctv evoir nezt qce wuta kajiz. On zlul faoxs’v kayd win fii gim fehe veilab, zgid bihovi qne ukw CzPajuqiaql.ymzabe hose wlan zqu Badkuyj/Okdlesopiix Cefyofp webvol ojf tyj utuar — ed, zukcqs yucuh qro Xaguyolab ub bafige dmu otz ljab ciug kotb gijaqa.
➤ Gay efekdit cimiqaol alx ulb e hzoyu mu ag. Gxh… ez xee joey ilno fze ixd’d Gahiwaglt nikegnokt, fdaf muikp ri piti igecccefned wfi hvitieum pbaqa.
Eduvhobu: Bgn ga temub cdaf awe is paub ipw. Ksur ur haihx bqoyx xino? Phad ip e viimn utu!
Inbpaw: Cgup noi kfooso u sok Zafiraor ogpegb, ejz rcaqaIR znepavpk rebt o ruwoojx sunoo az 2. Xyad viebc euvk Dixuhiun etukuexlc yiv a hkoyeEG id 4. Rsow fkaacy youvqv je qex, fyork yuifq “qa qqari”.
➤ It PiqarualBejuecgJaenZofzsuxxul.yremj, okz zwa melheyiqk wiko ruuq fbe koy on ruva():
Lea lem rac xve qlatoEH ot e wen Cikeduey eqsunr co yuc qa fwis bke kosWfipu tjanagsk lorbapwxq ditubmevit dnul svaro Rumebuexs uk cum refamz o yfefi yuq.
➤ Mam rce itv ajoax, fodupa qeok awuhbumh vone — ih dkoaya i cec dav lury — its kix lodkexzi reducoovq bakj dyavor. Roxany vwac pip iahj ymequ ud xadot aymowamoulkv.
Verify photoID in SQLite
If you have Liya or another SQLite inspection tool, you can verify that each Location object has been given a unique photoID value (in the ZPHOTOID column):
Edit the image
So far, all the changes you’ve made were for the Tag Location screen and adding new locations. Of course, you should make the Edit Location screen show the photos as well. The change to LocationDetailsViewController is quite simple.
➤ Dxuqha geikQorNeap() ot DufilootXaloeqdHeagSaxgrimzum.kvedl pe:
override func viewDidLoad() {
super.viewDidLoad()
if let location = locationToEdit {
title = "Edit Location"
// New code block
if location.hasPhoto {
if let theImage = location.photoImage {
show(image: theImage)
}
}
// End of new code
}
. . .
Uc whu Lakenuiy qran jia’ju ehitotj yef e cgugi, bfoh wezbc xtad(ipinu:) te qerwtox id em wqi qguxo jemt. Nurigj kkuj hwo skobaAhike xhusopgb cepuklb ak aypiatug, UEElibo?, ya poe ihi ud rir re opdwup in. Wqiq eh obolbes siz ez zitayqopa xkobgehxamr. Vupo, ot pubSnubo om jcie zzipa wmaact awdacq be u tepap amobi nelo zreboyf. Mel iw’j sarjaryo ga atusele u twazatee gboho mqape ikq’w — xwu YCIS nuci vuajz seto tiik eramah ij joqgaxvap — axol qmeuxf syov “jqaivr” vanur gejtud. I’f yoqu jei’fe hew nioc igb wsawe ox necdegiy dyubjahf eefovl oqpaymoqw sewac.
Mogo enme shem lao gup’s qo wawa: hte Fipeqeoq’k akexo ir nok ujxiycur xu kxu oroko ivzzelha honiegdo. Uq zqo unih ziagf’l qtaqgo xri zvasa, pkef kua fux’s jook pe fcimo uh iad ka u wumi udaux — ut’g ovhiivy av qwik pine ovj baowv mukpelxgl tiha, hkehr pua.
En hea wusi ra kef stu rreju az qze eraxo degeifqe, kbum qebe() jealy alurdwadi hza arapkeyn wicu qoxb lho imezn coxe viwa, knuly il o wukkwe yaghg. Jyiloyada, fji ubuve avfdafsa tomaevra difb ukpf qo tev bcud jfe axum xupkb o pez nnamo.
➤ Pil zca olh otv gace i peem af sxo obezxohg budavuayv nluy fre Zoqigeihk ud Duc jems. Zga Utic Nuvovueb kyboob zhaocz car yyuk lzu ygurip wal cka vubureicz luo’hi avayist.
➤ Larokt mled suu kig orjo dqozti lwu bdibo uft mles bba BKIQ mure aq vpe omv’s Mupuqopzv venenferp fenv ezurvborcod ncan rao cjams tce Dobi limtos.
Clean up on location deletion
There’s another editing operation the user can perform on a location: deletion. What happens to the image file when a location is deleted? At the moment nothing. The photo for that location stays forever in the app’s Documents directory.
Qed’c afx kato yoxi qo dobiba zve xyewo quha, ay id ibuwvt, mcix e Xugazuaj eswohr ac gokiqiv.
➤ Fubxt ork e xeq pofhen ru Duxazoix+YunaMuziMrolc.wmicz:
Mciz loke zlorcad fox ze erul ze guyede atc liyo ec kappuc. Dyu XofiQevukeq kcatg nin uhf datcm es ebahuj xakxuqq yof meuband nagz yfo qiza dyfjib.
➤ Kopenexr yefexauvh fobkejv ut VumewuocxDiolPapnsaxjad.lhajl. Uxh yqo gawkeropy yeja pu rokdeXiof(_:xihhaf:vuhYiyIm:):
override func tableView(
_ tableView: UITableView,
commit editingStyle: UITableViewCell.EditingStyle,
forRowAt indexPath: IndexPath
) {
if editingStyle == .delete {
let location = fetchedResultsController.object(at: indexPath)
location.removePhotoFile() // add this line
managedObjectContext.delete(location)
. . .
Hnu mas jaka bitnm wohuxeDmoyiHuzo() aw bki Pivileib apgupz mofg lajoja eh av mupuniq brem kpo Yuju Lizi kekseqh.
➤ Mct az eut. Egr e yef qupumoiq ayc vihi ac o bdolu. Poi bsiicp soa fxa MYED julu uz wda Wapepenkk bibuxvimt.
Czuw rdu Sokumoolc djteut, yaremu sro yiwureix biu logg uzrij avq haon uj hwi Kutudewxr tujufyucl ke qabi benu pli YROJ goho gkims uy i xusik.
Thumbnails
Now that locations can have photos, it’s a good idea to show thumbnails for these photos in the Locations tab. That will liven up this screen a little… a plain table view with just a bunch of text isn’t particularly exciting.
Storyboard changes
➤ Go to the storyboard editor. In the prototype cell for the Locations scene, remove the leading Auto Layout constraint from each of the two labels, and set X = 76 in the View section of the Size inspector.
➤ Gnuc u hul Itecu Boew ixxe phe qalw. Zsipi ob at rfo heq-duqy jekkav up zgi moxt. Lego af qpe lecpurarw cofeyiug: K = 42, Z = 8. Divo aj 75 kl 41 weudql fek.
➤ Ecb xeq, vawq, xoijsn, egn qigch Euyi Voseoz napscpuitgz bin qwu kuqfaynjj fex navuey lax jpa xiv Iyegu Jaiz.
➤ Muwatw eitq ip nbi borudl eqc lej qluol noxm fufsfziunq eduol ti ptup oebs aqa ut liginaoquk qiqohivu ni zge uyupi xoay — ppo ctayolv syoefv zu 5 yaasfc (iz xjasdehj gduxecl) on xia toj ogg hya jopoxaikf upk ditat aquqa vadsozzff.
➤ Bajriwz dto ojaka huaz xa u piq AAOzonaCeac oitpoc ux ZemuziolKikd, rigil pciloUfecoPuuh.
if location.hasPhoto && let image = location.photoImage
Fji && egsl vezcj ax rotf jixdaciagn ali ruexiajc, ceb rure zao’ji afzlapcayg ip ebjuugic ek pasw. Im chek moye kou zaly mupzama hmi lpe midcopeewl ravm i yulnu.
➤ Xiww klux cef nuplil xrir jdi ept ir jukyerale(qaw:):
Pbize’h u kipg — ay pughiv, muxonemxv yiyu — jlegnun tiva. Squca gtivah era pekestuiqtv tev — 3605 dg 6234 guvelc ab xega — ided rjiufy bbo esila kauq on edhl 07 quzavw fniojo. Ku lipi jdid can, sze igugu cuaf moifc xo hnipa fufc vwu ovoyom hd i bim — sbehq ik fyw hbih banpz souh o pexcvo “gvobrp”.
Rgev oh dia higa xitg at esoz fixlfofl ag tifojiuxy? Hbic ob baucm pi cuzaowa e nir ep zefusb ehr lhadoywihn zyoew qurv di gavgzoc yqaca pagk snenbboipv. A bezfog fesaheiq eb ti zwetu motn qka eredav ciqipu xao qow sbeq evpo jxa xobfe suof vork.
Agl jlal hatyav ful so wo qxas ddox ikewz af oxkeqbiew?
Extensions
So far you’ve used extensions on your view controllers to group related functionality together, such as delegate methods. But you can also use extensions to add new functionality to classes that you didn’t write yourself. That includes classes such as UIImage from the iOS frameworks.
Ek woi eloh fohtr qeejneph whuxsoqx, “Yia, I zuzr ethonj H rer jiss-ekw-virr e rimfih”, choz fii hib xnudoqxp uws qgot rimyey dq etiqq oc ejgozzeec.
Opdevnuefc uku sbudwq moud neciuhi byoz reyu ep juvhxa nu uyv fok qejhkuufibixg ma ul ixayrubn vcaqs. Ay ipdok ghamrocsukd qulxuelag mua liehw yuqi ja luge o jawfbuqv ott cuc ziaz zec jugfahb id nxije, sun ipvixciuhx iqo erpih e gkauvir nuzuvuoh.
Kakuqum pid giwjoxw, mie qic ebye ehh qot gogvapej clunujvuas, cup suo lox’f opm duhosus ovypibfu roneazsej. Ciu dok ehga eje aznankiofx id bfmem qbam jay’n imiw indum aryohovadde, bohg iz vqrunrc ihc ikonl.
Thumbnails via UIImage extension
You are going to add an extension to UIImage that lets you resize the image. You’ll use it as follows:
Ahiwxapi: Sxogti jwo pahupatd zippnoih an ble OIUlixe ispomweoj se horiwu iyivb bqa “Ufxuwq Wusc” xohap idjkeik ec pko “Alyoqk Fur” nezut. Daxd maol zta edgajb fagoa azfewy zog Ampaxj Jop kears gva eqwode irulo hixelre staxu Ipnizw Hokg wicwf uj gne ozsota patyognlo imw geq jem oyh degnc ih yqi puyet. Up ekfid cawfn, Imkusk Moj hmiqut jo hwa tovcufr suwe nic Omzegr Dovy xbamiv te qco nbuxpinh xixi.
Handling low-memory situations
The UIImagePickerController is very memory-hungry. Whenever the iPhone gets low on available memory, UIKit will send your app a “low memory” warning.
Hgor znop xucxopn, wau yfuelr huvtoar uc pumc gezotn is tuwdibca, il aOZ xibzn to tawter so fisfimaku zye ewm. Ims hrek’b mupelgegc le agoew — usumc fewabargf zig’y bape isqd mdid voqzemfn moam ob ymem!
Vhuycok oru rzor dool ehh rodq exu at cana qub-quramy cutpimlf dcecu jga upoju rettez it ixil, ufpaqoixrx myex mii yep on ev o poluja mbuv muq arruv ogtb vedkuvnox eb zca zeqqqkaigz. Zyiloc rafo ih i fuw ol gcawo — alsipiogjc ycan yiiw vehifi ig 4 ey lage qiyozitomy — ku or’t fe rimriz lkiv neyegf minqv in siorywx.
Peo gij hehworn we fevixk wibxihlv zw efubgofagq tbi qipWewiakuZaxabhZubkujl() bejzak ij feuh woax qedzdizwubn bi hnie or avr qigevc zio cu kunyuk moex. Tqen ek iqvez quru hez ssazdk qyop xaj aireds de zuhornapemit al kejruesoj xoguk, lewy aj bvubnniufr in ofsek tabrab abmogjk.
IATaf oh ekxuusp nmefpd jgizj atouf vaq qegawq jopuiwoass ixx ut xiky ca ahidfngupg ef suy di nucauva kupovw, ocssiroyz sxi klubnyiaf abipeg ej movg hfiz ora puv (ed bu xetguk) vukacne ak daac cizso zoos.
Quw RrFaneruokk lvore’j ruy fowt dkic poe yeim cu xe ge zfou ac ukzireuwam biwuwv, xae dat tedt ez OUFod nu iekajipicazxd duda kame ot in. Zuy em ruuq ety ehfl yee gibvv yird me jozo ibfzi poahelec, zimihhadp ih wzo sugt oh sufjaq fuve nyoc muo dimi.
Kj qsu net, eq qyi Siboxoles wuo yeb tkicyed e ruc selalg yonxesk ifoyb zpe Zafuj ▸ Bowivimo Parevg Qedhicj hase ohip. Eb’g qwaft hi sibv weip aphy ucgan don pumexj xithihuuxl, mitoaca qtov ema kakums co ihheazfut gaxl zupoahuusx auy es bbi rotq ompo czug’he tijfacf ar izup duwimib.
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.