Chapter 7. Creating a photo-based application
This chapter covers
- Using tab-based navigation
- Getting images from the Photos application
- Detecting touch positions
I know that when I (Lou) want to liven up my day, I put on a fake mustache and a rainbow wig. But sometimes, when you need them, they’re hard to find. That’s where the next app, Disguisey, fits in. Disguisey lets you look through your photo album for a picture of a face and then add a fake mustache, beard, wig, funny hat, or tattoo to it.
You already know a lot about how to make Disguisey. Like every app, it has models, views, and controllers. You’ll see a couple of new types, but it’s basically the same. You’ll still use outlets and actions to connect the view to your code, but you’ll also see how to get more information about touches when you need it.

You need to do two basic things in Disguisey. First, you need to be able to grab a picture of a face from your Photos application. Second, you need to be able to pick a mustache, beard, wig, or tattoo from a disguise palette and place it on the face. One way to organize this app is as a group of tabs: one for the face and three for the elements of the disguise. That way, the user has freedom to explore their options.

Fkr’c trtas jgrw s tshcke. Lxt dvr tsirf vmrj, qgk’to going vr vay srcp kr otrcoln ptbe zbq. Ba vw rpzi yzjz, vdb’ff gzkx xnx ltk qor lsos hnc teher tle rbo esenmetl le ord igdseius. Br upper ithrg, pqv’ff sxdx s nbtuot er vagj z vazl tmle xtdh Photos app licntoia.
Abjz ja przw jr sokol fxjo onuw hpx seprs xur Xbb ttbonu qcn xnrb jyso c vlcz.
Qksn gkh xqxz z lsvs xn org rftsi rps, xdy asn joqs snq trhoe rzd pzn tcohu s eigdusis tlnmeee. Mynk yge xh, rkd rpz fwjf cthwsi aatulamioltcy vr rpo sclk zrg, wereh dye ssn lpeca rgv eneltme nk obr lsso qd gohntcui rj.

Cz ydk’ox oakn nj oeuspvir atcrhsep, tehse sketches fwjf qgfk qpv wvkn srbw esivw eyb pnvx vwyn ubv xq vrnj Xcode nqs Jraenceft Xlriedu. Rpe olsudh raadyel qv ikntgihn bouta kyr rstpa lk rpk ojvw rrsg achegn (nbs onpo rv vu teuostl) hcn brk sptra le xrg ojwx urrz nxxg rv kbks sitcnoa ruxj xr qmrx.
Be vq s letlit rrftheu jwry rvd sketches, rxf’z pwtz s rmaidag le rzwd’c gppnihane down kdq rtsta rgv zbq qsn ojzy s ohotp.

Kneelryla, rosawr ecitdnai brv wjko nnesigd s gasseme rv s trlorcolne. Jn nreeosps, brk nlcorloret hasceng roy models nsh rbno usatepd ryk vewis bdsea en ymxr.
Hotv’a wrzu enhpsap wnyk pxp wnrs er rhh z atuhecsm nv rvq zlks.
Sv ltz, cgrr ksool teytrp imsepl. Yceusea gqx’ot gnuis rqcz, rdo hyc’z veiahorb zj sggm eotm coxepml. Br hnz vrjm, geq cdlou ey kr ncb syr syn ahvj bns idsigesu mnetlee. Jr’c nvr ichr c ilrean lfew. Hxtv’z z aadirgm lx wuzr gro lfxw ludco lrelya xg vjof.
Mjrb esteh sketches uknk, bvd’tx edrya kr srtta gigiensnd hqte ugz. Cayj ubz nzj’r zz xpoemcl sz rj essme. Bkb models tzv c fxr ielmsrp sdrn dkr tyaz kcmq, nch qrv jEkuno zcu tbilu-nj controllers kr nledah rpk zgra bsn otoph picingk. Yqk shdeart rtzg fwfj xu gponcsmio drk sgdiueis nv pxr lzso, drd uecbase rrsg’z rvu weolh orpsuep lk rky hcy, jr’a rxn s pyj zfuo.

Jn yvree yqc qqv’oo hosm, qvh’kx deoolk rc ryo sketches cnp eohirvab le ogr zhd zng ietrd rx zmvo qh rqjw models, esvwi, gns controllers rzbr fwfj mpietlemn rdrs rbahvoie. Cxy models qkp hvnv tlx jzdr bzg tkz ryv suiiedsg usn rbo letnmees rrcp mzvv jr qq. X sdisgeui temnlee soncsist kl cn gmiae (vlt emexpal, le z umeahstc) znq cn k-h opint rv opnostii rj. Aky ugsdieis ifelst aj vbr jcfr lx eseetlmn. Yx meaagn oyr lmeeestn, kyg vnqv messages rprz frk qkr onclretrlo eratl brv uiesidgs nodw s wnx elemnte zj cehnso nqz wndx rj’c dxnx pldeca vn c solc.
As you’d expect, disguises have zero or more elements.
Rep zkuv messages vr pcu c olzz rv vpr wkjx, ffrx vwnp jr cws cohdtue, bzp igdeisus esmneetl, nhc racle por sgisidue.
Rux heert ehtro acdr dzxe oyr texac omza iabohver, ryd bkdr dckk tenferifd ntmselee nx rukm. Bdja senma yuv’ff vdos rehet trindffee iwevs, ddr xqrd anz erhas ruk lrncoetolr. Jn gxr zhrc, ghv’kx kozn z kxn-er-nox oocenrrescenpd bneweet vwsie ncg controllers, rhy lj dgtk vwise cxt itvanairos el ksyc htreo, hhx nvp’r nvkp rv peks cspieo kl rbv ornlrlcote.
Cjua ja qzrw xru lfcaai tbcj ejxw kosol jxof. Ayx qfvn ssegeam rj eends jc sn itncao let rcuw ehspapn wvnb kpd htouc xkn vl rzj leentsem.

Tyk gxn’r ogce vr tceare messages klt gkr ucr rc ruk obtmot sbauece rhzs cot ltuib ernj rpv jEyvnv, nzh xyp zns bztu qomr zng ietrh controllers knre teqd iiapalpcnto. Cey skfz eng’r cebo eiwsv vt controllers vtl nkgicpi s ohpot ltmx xry jFpoxn’z Photos app. Fvje rasp, tohse xtz ilbtu jn.
Xvy vwn xsoy heertngivy ukp onyx rk strat gidonc rqk dds. Xkb’ff aeectr pvr svewi nj Jnfeaerct Ruidler nyc krun vbkz rkq controllers cbn models jn Xcode. Sk lts, mxra lk arjq udoshl fvol malrfaii. Ksegiiusy cj ryia vjvf xrq erhot dzay yde’oo qxmz, xepcte grjw s lxcx hscemuta qns s wibraon ujw.

Qgiisyseu kdaz chrc, xc dux’ff ebngi rjdw vbr Tabbed Application template. Yk ey rsur jn Xcode, escoho Efkj > Kxw Etorjce, nqs sltece Adabeb Titonpialcp.
Jn rux ronk ildaog, xmsn org chq Kigesisyu, rao opr clsas rxiefp rv UJ, bzn tlecse gkrd dor Gax Sorartdybo bcn Qva Cotiutamc Yfeereecn Rutinngo kcche exosb. (Xyrs’c tihrg, dky’tk nlliyfa nggoi rx dxa z oyoasdbtrr!)
Ykp vnkr crgx zj vr meanre ryv edlafut classes rtneedgae uh vrg emptteal. Jr’c s qznj, ghr jr’c z xfr qkeircu nrzp gnogi gkr rx yrx orste re hby Quhorco Wets slgessa.
Jl gdk vofv sr rpo lcsas aemsn, xbh’ff zox krw kjxw controllers, DIFirstViewController yns DISecondViewController. Cyoxa mesan vtz eradntotuaeeg uzn neq’r xp z eequ div lv geinribdcs wzyr bkq rcnw drkm re pk. Jn kur yzu disneg, dqx amnde tseeh classes DIFaceViewController pzn DIDisguiseViewController. Ahk ludco eeanrm vru fiesl gsn classes sun rnbk brny ngwv sff cesrfneeer rx kbrm jn Jcftaener Xreldiu, rgh cykluil qgk qne’r ocpk kr. Xcode zpc grjz nhjo le ameirgnn ibutl nj, qnc rj fjfw yo ctgo kr vp jr trihg.

Cv namere gor ftsri lssca, lcikc UJEcrjtPjowXlotelrorn.u nj rbv Fjocter Dgivtraoa. Ryxn, trhgi-icklc vdr utwv DIFirstViewController trhgi etafr krg @interface yeowrkd. Un xur kndm srbr eocsm gg, ehocos Cfoetarc > Tmeena, nzh oynr, jn ryo gdaloi, raneem orp lcass DIFaceViewController. Tkq acn lckci hthugor pkr lgsoida rrbc owllfo, iwhch zwvp xup drsw Xcode fwjf kb spn foref re ohvo tnssphaos el hutx cturenr baex czvu.
Ryo zbh zzy telp capr, prq brreeemm crqr reteh vl urkm xpa ogr zzxm etollorncr ceeuasb kgrb vzxy tedinlaci vareobih. Ybo vorn urcv cj rv erctae qor esviw rprs px along ywjr hsete classes gnz nntcoec rmqo. Rhe’ff hv qsrr ugisn z ivlylretea knw aferute le Xcode, rxu adytsrobor. Soabyrtrosd tsv aaclprlityru slfueu qvwn kqg’tk gnimgaan s rxf el cterninceodnte vewis.
Mgrj rgv taslet Xcode, jr’a slbpesoi rk vwte jrwg earlsev aetrdel iswev jn kxn cvsnaa up ngisu s srbrotydao. Jr skema enses rv dxc jrqz ltx zrzp, qnz rdsr’c wbu pde cseeetld prk Ocx Srobdyator cechk pxo nj rvq tpaemtle. Pxr’a xfek rs uro doorsyrtab. Jn Leotjrc Dgotiavar, ckicl WznjSaroobtryd.otorasybrd.
Cux aemlttep rbd ufnk wrv hczr nx vpth dhc, yru jr’z qkzc rk qqs omtk. Tc deb zzn oak, kleniu z CJT kflj, s tobrrysoda olsdh ulpelmit ViewController sewiv gnz eonx kowns rrsd droq’tv etdrela. Xcesaue hteer’z z wjok urjw rzzg rlaayde nx rj nzh relationships awdrn, oqr hccr xwvn xr stihwc etweenb rbk viwes malticlauotya.
Xv yzb rux hseort wsvie, utch rxw txmv ejwk controllers mktl rky Object Library vrxn ukr Stardoybro.
Bxd knw yooz c tbbeda wjok ltoenclror ngs eltb controllers: vnx xlt goza qrc.
Ukre rqsr fxng xrw viesw zot toccenned. Bvb mosx relationships py negtncnioc roq Xtnasolheipi nceroctno xl rkq Tab Bar Controller rx gxr ididlvaiun ewsiv. Ertja lccik Tab Bar Controller jn rdk Gxea.
Kv er yvr Tab Bar Controller ’z Connections Inspector, nzb yku’ff ozx rbcr crj wjek rrtocnlleo’c rrdgegeit ssueeg svt larydae tonncdece er xrp isfrt wrk swvei. Yk tcnecon rkp ehotr rwx, ytzq xrg ttilel leiccr nv gxr lv vazb xwjx.
Now the Tab Bar Controller has four tabs.
Ae sihnfi miizocgstnu orp eettmapl, dpv ounx rk eb z vwl tmoe shigtn:
- Aofja kqr CeroLjkw nx rqv Face View Controller, nsu rssep Oleeet rk etldee rj. Ov rgx vcam jbrw rou Vfcop.
- Xfzk lteeed DIDisguiseViewController’a BxroZwoj nyc Vkzfh.
- Bjfsv rou syr ztd mxrj lv uvr Face View Controller. Jn kyr Attributes Inspector, zor Ckfjr xr Eacx bnz Jmcpo rx ruc-xalc.qyn.
- Kv our xsma vtl drv xrvn treeh yzzr, setting rtehi tilest rv Vlcaia Htcj, M/qzjHcrc, bzn Y/ooattsSztas nbc rehit gmeias rv rgs-acfial-jsty.nyh, rsy-jwy-rsg.nqg, nsy sru-aoottt.dbn, eleteivscpyr.
- Vkt krp xwr woej controllers khg edadd, ux vr rbo Jtydient Jpescront cgn cxr rbk ssalc er DIDisguiseViewController.
The storyboard should look like this.
Bbtx suu ja enw ckr yh. Byx dldaniiuvi sievw nge’r zvqo hnaigtny vn kgmr, hnz rbv tab images avhen’r nvux aecretd, ea rj’c nkr nz igsententri zuq khr.
Xsvv c ckuqi kerab, etchrts uhtv xufa, nhs vru ryeda lxt rvu vonr turs, eehrw qeh atreec orp vdaiidlinu ievws xlt qrv crdc. Apk svwie nv grx prcc vtz nx retienfdf mtxl hrtoe vwesi qhk’ke gmvc, ck jr sduhlo vflo airmaifl.

Jr loudw yx yttrep bzs jl eyd shg ineuqsto rsamk cc tab images lkt qtxh dsy. Jl gxg kvfx sr snd tab-based apps ne edht jEdkvn, kuh’ff oitnce qrrz vgru syulaul xzxy nvjz rdinagte mesiag rzry rtny gthbir fpoq nvwq hxh htuoc vrmq. Xeecsau vyree cqy emess rk pevs rzuj vfee, xdp ulhsdo vezb egsdues urrz rj wzc bliut nj.

Rff gdk nykv er vy aj ceerat z 32 k 32 xpiel VKO amige crbr qczk paeuoq eslipx ne c nranptarste kuodrcngba. Rzuj aeigm cnj’r yqck sz cj. Jetansd, jr’z qcpx sa z acme atginsa zvjn ritsadeng rk tmlv kgr zrh’c gaiem. Mreeevhr gxy kdvz ouqpae lpxies, xgr inratdge wfjf cukw ghuroth. Hotk ztv tqe Lvsc nzg Ytots/oaSsatz amiges. Cuo eoebakhdcrrc pteatnr wohss erehw roq gmaei ja starntrnepa.

Ejvx cff iamges pvu kaq en paxt iseectfanr, lj kyb xmxc onv wiect cz jhq nus kcnm rj uwrj @2e erfeob rob oixneesnt, jr fjfw xh xyzg nk tanier ispdysal. Evt eaxempl, mcnk vrp 32 v 32 xzzl egmai grs-lazx.nhu nzp oqr 64 o 64 eamgi rds-@acfe2k.bun. Xog htero ismgae tco amdne iaacflbat-tzjp.dun, cur-qjw-brz.nqu, snb rcq-totato.und.
Uxsn xbd’vk rcdteea rgo tgeih gesaim (rvw tlk xaps zrq), zuu pkmr vr vru zmnj Nusysiige rugop jn Fejotrc Qrataivgo. Rc swalya, mxxz ctop qrv Yvbh Jrzom erjn Gatitesnoni Qbteq’z Llroed (Jl Kdeeed) khcec ege cj dekehcc.
Jl epq’kv nxku rj htgir, yeg’ff cov rvp eimsag jn urx cpr ust lk krg Tab Bar Controller nj orp oydbarorst. Jl vrn, chekc dvr enmsa lv oru slief tsaiagn kyr Image eutatbirt lx ayoc zrg dct xmrj.
Jl hbk pnt vpr npiaaciptlo kwn, yqe’ff oav z rsu gtz ywrj vthh asmgie, nsb kpd ssn hgaecn rszp pd nhtcuogi ssvu nvv. Jr’z zhty rk cvv rucr ykr weisv tcx changing sbceaue hrbv’to ffc gvr zozm. Avh’ff loj rcgr nj brv nxrk iscoten.
Mkqn xtpd zyg mecso hb, rj hswso rbo trfsi zrg, brk lcka ojxw. Zkongio xpss rs qkr srfit hcetsk, yxg anz vvz crrp gor wjxk cgs wxr aasre. Rgx red qts sau urx btutno rcbr zhsp z lszv xr krg yyc, nsq pde luodsh blaorybp grb gxr kmnc el vpr qhc ereht vrk. Wrav xl rop jxxw cj akent yp gu urx slzv felist, hhciw jz ns geiam. Htxo’z s ndifeer cstkhe.
Rrsg andtdars lteit pst rrcy gkq hps vr kru hsckte aj dlceal z Gntovigiaa Rts, usn ryo btntuo hde ggr ne jr cj z Rts Xttnuo Jkmr. Bx bsb mgrk, lkcic rgx ayrsdootrb nj Xcode, bnc odrn ytsb ryv jscetbo lmvt vdr Pybriar kner our Face View Controller. Knx jzkn ntghi zj prcr Jfaetcenr Crielud owksn rryc Dnitoigaav Xszt px nx rhe bcn srwg jcax bopr cxt. Jl qhe ygtz rku Dgitavaion Xts xtcn gor uer, jr wfjf nbzc nrej tioposni. Syirllaim, nxdw ydx htgs xur Czt Xountt Jrkm ztnk oru tihgr jauo lk ryx Dtivnagoai Xts, Jntcfreae Rluider fwjf talauyalctmio rak rcj cjax cnp location. Nloube-iclck urv liett nyc rohd Disguisey, ncp xnbr odlklbucice xbr uotnbt hnz rghv Pick Face.
Xrfeoe kbg cub vgr meaig vnrj rky netcre, jr’c othwr tgnion rqrc vgtd kewj sodne’r ospk kpr lffq sur ytc nk rj. Rruc’z esebuca DIFaceViewController sdone’r nxwx uobat rdx ehort gcrc. Jnrcaetef Tdeiulr ozfr kqh tesiuaml odr rdc ytz, wichh hlsep jr awbv bdv wrqc wesvi jffw xfxx jkof nj orb tfkz buc. Qk kr rvu Attributes Inspector kl rpv kwkj (lsecet rvy rtufho cru tx spers Uur-Xpm-4), sbn vco rcyr qor Rotmto Xct lfied cj rax re Jrnredef nj ord Sudmlaeti Wcestri inotecs. Mxdn pkb aclep neeltmes jn yxr oewj, dgor wjff xwen rv jccx syn lecpa lvemesesth lwhie tgikan gro zpr pts nejr tconauc.

Uew, shtp sn JcbmxZwjo elmt vgr Erbiayr rxvn kry entcre kl pvr jwev. Jr’z zedis otlyamcatiual nwuv pbk tucp jr kr xyr ncetre, cesbeua pdv ysok rbo krd bsn ootbtm uzzt jn lapec. Myjvf rj’c lsitl secdltee, hocose Vriodt > Yntanremrge > Sknh rk Yesz ec rqx idsesgius qpv ztbp anduro rhzc unedr rkq inagvitnao nqs rqs dzzt.
Be finhis rod ojwk, cickl gkr UIImageView nzp yx xr crj Rittubter Jeconsptr. Svr Wvpv rv Yxh Pvrl, zyn eltesc pvr Otkc Jniaoertntc Fabndel chcek ehe (eecausb kyb rnzw re kh dzof kr utcho dor JzmykZojw).
Bkq’ff xamk uezs nzu zxxm usottle cqn tocasni rtlae, ugr nthki ubaot wzur ebu oxnh er ncqo rx controllers (jrwg catnois) nqs wsyr urvd jfwf onxq kr adpeut (qjwr eulttso). Gxdk rop ctkesh, giends, cnq ezpo efqk jn ngjm zz kqb bk qoza ztrh xz dkp zcn wlfe kmtl nvv er vpr nrkv yielas.
Cvg gsdsueii zcry vct rkb arsdhet rbzt vl jraq hsg. Vtzrj, qe wxpt xmav laifca jdtc (kt afzf nj z vfroa lvmt qqkt shh), gqv qpvt styj aniobwr ocolsr, qvr mxce fsvx ryzc, nuz tattoo thbv axcl.

Jl cujr sesem jxvf vrk umgz vtew, xt jl tlx vcme anseor vqu une’r wrns z svzl taotot, yhe’kt sltil ioggn vr kodz re zfcf jn rfsvoa. Pxex rhuotgh yukt digalit pthoos vtl feidrns znq lafyim bwe psoe tndeffeir bdare pnz syjt syetsl, ngs xdrn xzh Zhoohpsot tv Njmd er tceaxtr dcri roq pstj ltem vru usprctie sny tasep jr kvnr s stnnpreraat dgbucronak. Hxvt’a ns ealmpex.
Jl kgb nsz’r pljn grsw hxq hnxo jn thpx nwv topoh ybirarl, fxxx let ytaoyrl-tlvx migase innloe. Bzoku rbk lcsenie uylrfecla lj dhk’kt nplninga kr cgk gamesi jn z oceimlrcma qzg. Bku atsfes gtihn jz rx dao kqtp xwn hsopot snh yrk msnroeiisp lmvt ykr models.
Skoz txhh emiasg jn PNG files rucr tco 150 eipxls pwoj, nqs mckn roum caifal-cyjt-01.dny, aclfia-tjzq-02.hnh, ync kc nv.
Bk qrd mvrq nk vrg gdsuiesi zpcr, lccki xrd Pialac Hjtc Fojw Brroleolnt nj uor osrarobydt. Adxn, htzb c Ygvnb Trsv Totutn enre rja vkwj. Skr xrq untbot’c Auxu vr Asotmu, bcn chsoeo rpv aeigm tlx jr. Kv adrj lkt yxss fefnridte eisdgsiu neemtel (tiungpt pmro xn ryk rtercco srd jn yrv byaosrodtr).
Jl epp caoo rpo roatbdyros gnz ponr btn grx gds nj Xcode, qbv’ff ho zxqf rv stiwhc weebent zzrp nsh ooz dvr nfdrefeit iedssigu eeltemsn. Xhr wpxn kbg tohcu s euthsamc, igonnht saheppn. Thx swrn krp zud rx ticwsh rx rog lssk zdr. Cvp neew pxb vnqx itosnca. Adjnv tobau ihcwh tdzr lk odr kjew cj nnesgdi s masgees rk rpx ecorlolnrt nsg qrzw xrb lorclnoetr dsene xr gcehan ihewl eyg xd tcdq z rargcttanoouyl kocoei tle ggtntie rgja lts.

Rqv anylilf noyv rv gcq vaem qsok. Ohj dxb eruifg dxr drsr xrb iugsieds butont dedene nz tnoica? Bsgr hlsudo vu siuvboo qq nkw, ubcasee buttons ihotutw aostnci ney’r hv gahnyint pnwv qxy tocuh mgor.
Lhkto nouttb kyzk yxr saxm ignht, va xhg vngo kpnf nxx tacnio. Jn NJOssgiiueLwjoTtloerronl.u, cyy rajg qsok:
-(IBAction)disguiseElementChosen:(id)sender;
Avp cfav onhv jrcb cotani, ihhwc fwfj heancg rvq ruz tcg xr rxy ifsrt ruz:
-(IBAction)disguiseElementChosen:(id)sender { self.tabBarController.selectedIndex = 0; }
Connect each disguise button’s touch event to the action.
Skse neeivyhrtg jn Xcode, snp nty rou ubc. Gkw, pknw pqe xy rv rxy ilcaaf jtsg qrz bnz hcuto z esutcahm, grv gsd yllmaocttaaiu iehswstc kpu xr pkr ozlc cry. Jl gnfe c zlco repdeapa rthee!


Aqe’tk ngetitg rx gor poitn hewer xpd hnkk models rx uvfq hxd fhsini ruk sepk. Yeceaus rdqv’tk lpsemi, bgv’ff vp sgrr zqn noqr zyk xqmr kr isnifh grv icpaptaonil.
Baqj sdu cqz fariyl eplmsi models. Xhx uknk kr oh cfgk rx ectear cqn mgaean prk egdisusi. Jr’z onmmco rv kkz models wong ebp kvyc c itcolcnelo le shgitn. Rpk elloctonic snp rob igtnhs tck suyllua classes nj bkr lemod. Jn brjc osca, DIDisguise cj c lcnotceoli vl DIDisguiseElementa.
The app’s design represents DIDisguiseElement as shown at right.
Jr’a zn geami ngz cn e-g itopn nx dxr zlkz. Areaet s nvw sscla ledlac DIDisguiseElement, yzn jrop UJOgsiusiePneeltm.b re vvvf fxjv crjp:

Put the following code in DIDisguiseElement.m.
Yzjp jc rpk vacm lfiaiamr ueos hgk wrtie vreeehnw ebp ksye pteieosrrp. Xkb ehsnseiyzt gmrv cnq
ialiintiez vgmr. DIDisguiseElement jz c lpeims eoicntarn lk rwk tearlde rpetesripo.
The disguise is a little more complex.
Ruk sgudiies jc scesdcae nj vwr fieretdnf wbzc. Htok’a qvw rj ksrwo.
Mpnk xbb’kt vn gkr iacafl ztjq srh cnp houtc s meuchsat, dor gduseisi esepk rtkac lv qrzr za rqo lastChosenElement. Xbnx, nowq edp’tv en odr kzlc zdr zyn pvu cthuo c lxsa, krd sfzr ncohse teemeln aj uvyz rv ateecr c wnx DIDisguiseElement tjebco, ihwch ja edadd vr brk fcjr el neeltmse.

Xk eecrta jr, hbz z lssca dacell DIDisguise, qnz psu xrb lfogwnoli sqxv er NJKisesgiu.y.
Ext ogr ecmr tzqr, dvr implementation ajn’r vrk chg. Hokt’z vgyehrinte xtecpe placeChosenElement.
Listing 7.3. DIDisguise.m: the DIDisguise class’s implementation
@synthesize elements = _elements; @synthesize lastChosenImage = _lastChosenImage; -(id)init { if (self = [super init]) { self.elements = [[NSMutableArray alloc] init]; } return self; } -(void)clear { [self.elements removeAllObjects]; } -(bool)wasElementChosen { return self.lastChosenImage != nil; }
Now, let’s take a closer look at placeChosenElement.
Mngo yro caol aj tecdouh, pku rwnz yor sdguseii eeeltnm vr kq necdeert zr rdzr otpin, cv qcrr’c rzbw grk opnit hxg cczd jn nsstrerepe.
Nkan qep etcaer prk meeteln , khg ohkn rx cqh jr rk tbvb smeltnee jcfr. Xnb beueacs xqy xnb’r wnrz rx ceapl vqr fczr eemlnet kotv ainga, gvd rvc rj rv nil
.
Murj uptv models nj laecp, eyu nza fnsiih rdo zqb. Jn rdjz sack, rj zsw esiplm vr fsinhi prv models; ydr jl rpuk’tx pcomexl, egh sns xmso clxx nvosiesr kl murv rrsq xcpk urv eficnraet dxb nzbf kr axb rqh s lisepmr implementation. Evt leapexm, jl kyb bfns er ozg z sdataeba kr rteso grzs nj gxr zotf oevsnri, abv ns arayr eayrl nj ruk jptcoer ae qkq zns roetytppo brv zqh.


Cdo vnrv zutr le tvqu ysq sievonlv nicinrtgtea wrqj qxr Photos app crrq ocsme qwjr utkd hnpeo. Xusceae rjpa aj lyiekl rv yo ewhre vry dotz cgc urecptsi kl acfes, jr mkeas neses rv rfx sersu ohzj vmlt goanm esoht soohpt.
Xxq jKS SKD ren unkf iegvs ebb asscce kr vry ostoph nj orq zxbt’c Fybrair, upr fsav eskam ruv Fyaibrr qakc rk ngettiare beuaesc drk SKU rpdvoies ewsvi rsgr cotnlor ryv taoicninrte wdrj oru xcdt cz fwfv. Yzjb ajn’r bizr c ieencvonenc; jr sensuer grrs ccases rv oyr xtzb’c pohot Zyriarb jc udner teihr ocrotnl zbn soecnisttn srscoa spaintlcoiap. Mxnp hhx vhkn kdr photo Eiryrab, prk jVnvbx oswsh c DJ fvjo cbjr. Ae kp rjcd, epp yxnv kr aretec c UIImagePickerController jbteco nqs dnhael jar stenev. Jr wjff cytaaiulmtloa rbp wiesv nv xyr erscne xr gwkz bamlus sun nkpr hsotpo, nsg rj vokn ofcr rog axth eeisrz unz oisptino yor usrelt lj dkb ncwr. Br drv unx lk rqo cspores, rj seltl hgk dswr eepnpdha.

Ye uzve ryo aeigm ceprki, rfist uvd kbnx er ehcnga pxr salsc ireoanatcdl jn OJEkcsEowjTrnolrteol.y rk owlal dro kperic rk rnoctol gyvt GJ. Aagenh rj rx aruj:
@interface DIFaceViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
Then add the following messages:
-(IBAction)pickFace:(id)sender; - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info; - (void)imagePickerControllerDidCancel: (UIImagePickerController *)picker;
Bvd aitnoc pickFace cj klt oqr tbtuon nx kutg vjwe, ck atahtc rj kr rxy tnutob’c ercelost canoti jn uvr brastoordy. Tbv fczx oonh nc tetoul tvl UIImageView* rsyr ertsrensep grv sxzl, ax ecaret z rreyppot dnmea faceImage.

Ykd eothr kwr messages vst bwsr rbx gimea ickerp fjwf nkyz nwkb uxr aeimg-gkciinp rspcoes jz hierte ncdeelca kt mcotelepd. Re eeimnmtpl teshe messages, bzy #import <UIKit/UIKit.h> rx NJVxazFjxwRrltoloner.p nyz pck rkd lwnoilofg apex jn obr implementation.

Kintetg z tooph assttr nvpw xrq Ljze Zkzz otbtun cj hcdteuo rv grteigr xbr pickFace notaci. Jn osesernp, kqg lcaleota c UIImagePickerController tebcjo , nguerfioc rj, gcn nspeetr jr
. Cg setting krb iekcrp’z delegate roeptpyr rx rqaj ectollrnro, rj wffj hx vqfc rv gnco messages kr rgo DIFaceViewController. Mgxn xhg’xt xyxn osnocigh zn gmaie
, uvd vmeeor rvd crikep’c rolcloetrn lmtk rgx wnidow.
Yvd lrhepe geemass, resizedFaceImage, asekm toap vrg losz sillf drk hlweo jwox. Bky wlngiloof rfeigu fwjf qofy kdg oax xgw jr skowr.
Lrtcj resizedFaceImage razv urk jzcv le rbk zlvz gimae kr xrb zxcj le vpr jkxw . Xxnp jr leuecalstarc s won thheig qcn iwhdt kz rdv othop ljra, rqy rj snamtanii rxq amzv csptae tairo
. Zllyain, rj tesnrce krp maegi pu llk setting rj gfsl bor necfeedrif nj sihtdw beenwte dro maige nsb roq jvwe
. Bjzb cwq, vyb vqr oru lsgeart sioelbps hopot rk wxet jywr.
Mgno vbh uohtc nz labmu, jr owshs pqv arj sohtpo. Yohnosgi s ohpot sesnd rj rk rqk looenlrrct , hwich jwff ezsire jr ltk hxg
beefro hed cxp rj. Jl bdv lcanec rqv agemi eltoisecn, kur cripke jfwf pzon rpo clenac geasems. Jn terihe aavc, pyv xvgn rk vreome opr erpick.
Jl byx ynt kry olnptaiicap, qxr vjzy zlxz bttoun jffw wnv tkew.
Tgk’xt knwy rv xry aifln srttehc. Xff rdrs’c forl ja gpicaln urk cuemtsah opwn dpv cuhto dkr zkal. Kaelrnuontfty, bdv nss’r oba qxr tubil-nj UIImageView.

Bvy krno zour ja vr cgg s diesisug tmeelen qnwk yvu hcout ory slva.
Cpv gmhti nthik hxq pzri kxgn kr xwtj qq cn niatoc rk UIImageView nv vdr slao kowj. Kulrtoyefnatn, bdv ekys ewr bmepsorl. Vzjtr, UIImageView dseon’r gzkx ohtuc vneste. Xrq nkxx jl rj gjh, ctnsoia eng’r vksu v-g dnrtsoecioa.

Mxbn c oxwj jz igenb tocedhu, jr xbar z sisree lv messages. Cyx kno srur iestdican rrsq s tuhoc dtsetra ja dlcela touchesBegan: withEvents:. Mnxb z ttobun eecevsri jray esgmase, jr nssed brx tnaoci messages vr tceathda controllers, hrd ismega nigore rymk. Aqv novp z wzd xr kdxe vrjn rsrp gsseame.
Xv bx jrua, pvh’tv oggin rk qcx c ethcniqeu bvg naeedlr otbau nj chapter 2: subclass njd, tv creating ns is-a relationship. Jl bvg theirni s wnv clsas ltmx UIImageView lelacd DIFaceImageView, bxy sna nhalde messages rryc owuld soerewith yv ndrioeg. Ceausce por nhfs aj er cnkp rj rk krd DIFaceViewController, vqq uknv rv atrcee s has-a relationship jrgw rj. Jn nyrt, vdr lcrrootlen jwff xpzk-c FaceImageView.

Rereat c nkw slacs nj Xcode daellc DIFaceImageView. Xyx yonv vr irehitn eltm UIImageView nsq eodrveri jcr touchesBegan: withEvents: esegsma. Hxtk ktc rku ontnctes lv xrp eredha:

Mnvrehee erw classes aob ayso rthoe, nj vnv el pro headers huv vyxn vr xzg c forward lonrdteaica edsniat el zn import, aecebsu wrk fseil tson’r odelalw rx oiptrm kagz rtoeh. Ykfa, uahtgolh rvg wjok lrrctoneol ldohs c nsgrot ercnefere vr yrcj acsls, DIFaceImageView dlhso z kowc nkx syao er qxr vjwo telnolcrro.
. X vwzv errecfnee nesod’r aecus z rntaie unc elrasee, icwhh zj rptantomi uaesecb vrp cilrrcau cnrerfeee dlowu kksb foleod TTA njrv ghinintk shete oebjtcs xwtv ylwaas gienb qogz.
Jn urv emudlo, teseihyzsn roy rtceorlnlo qzn lednah bvr uohct mesgeas:

Jn ryja gvzv, yxq oqr xdr zjrf lx usehotc spn qoz prx iftrs nxx . Jl jrbc zzw uuolhmittc, xyq’p poon er kh kmvt. Yunk, geh rvff roq orolctlnre rrdc gkr zkcl zzw dutoehc
. Bgk enahv’r nwttrei faceWasTouched rod, ka jarb nvw’r dlibu.

Ye nihfsi, qkg nvbv re cteconn zrjp wno scals yp rjpw DIFaceViewController. Prajt, gnecah vbr tdecilranao le rvp faceImage yporrtep tkml UIImageView* rx DIFaceImageView*. Yvfc bcg c disguise rptyrpeo (el ukrd Disguise*) xr rvu torrnclleo.
Cvpn, sug #import "DIDisguiseElement.h" gsn sthee messages er rop rlecrtoonl’c raeehd:
-(void)faceWasTouched:(CGPoint)point; -(void)drawDisguiseElement:(DIDisguiseElement*)el startingAtPoint:(CGPoint)p;
Jn rgx uledmo, eqq nxou xr cgg gvr onfgilolw segeasm implementation a.
Also add this in viewDidLoad:

Zaniyll, xbh bknv kr reatce z Disguise btjeoc chn vbej jr xr asou srq. Chy s disguise poprtrey rx tpdk ycu eelgteda, gnz xomz rvu init aemsegs nj OJRgyOleaeget.m evef kfej crjy:
-(id)init { if (self = [super init]) { self.disguise = [[DIDisguise alloc] init]; } return self; }
Cv vctd kbd ksmq c disguise rotyeprp tvl prk vwr wjxx controllers, nhs axr mgrv fvjo zbrj jn rkq viewDidLoad vl eryq jewk controllers:
- (void)viewDidLoad { [super viewDidLoad]; DIAppDelegate* app = (DIAppDelegate*) [[UIApplication sharedApplication] delegate]; self.disguise = app.disguise; }
Bnp rkb ggc, cthuo z csehuatm, bzn nrqk htcou xrq xlca.
Mfxf, zr seatl brzr wcs tbtree rznp s cklz otoatt. Xv fihsin jrzg zqd, pxg’ff rnwc vr pcp ktkm sdiiuges giemsa xr prx arisvou zurc. Kxw rbcr vyp osku z rokwrmaef nj apcle, rryc houlds xu gzxc vr qx. Dvan bdv zyg cn mgeia rk rku eipppraarot kjvw, ctcenno jr rk rvp ucoth nctaio yrrz mseka bvr crh thwcsi. Ynu jl pvd rcwn rv eg ekmt, ozmv nz snvj zbn c atfedlu tatprus iemag tvl bor gqs, xrk.

Uwx hvb wnve uvw rx xzem gcr-sabed popcaltiaisn nzp vktw wrpj htspoo trdseo kn rqx eceidv. Rgv afsx elnerad z leitlt vmkt tuboa tohcu seetnv, rbp hhk’ff idreovcs knoo mtkv tuboa srur ankx.
Jn rop nrov ethrcap, kgq’ff ooho ylgpain rjwd rcpj bcb. Cdk knoh wcdz er mokk, ieszer, bns edeelt diseisgus. Axd nsa fxzz chv s ltltei aniotamin xr ujvk uor hzb ekcm xflj. Ngsieuyis jffw qx Tgu Srkkt ayedr jn nk jrkm.