Chapter 3. Coding in Objective-C

published book

This chapter covers

  • Creating classes to match your designs
  • Declaring and implementing messages and properties
  • Connecting code to views in Interface Builder

In the last chapter, you learned how to go from ideas to object-oriented designs. In this chapter, you’ll learn how to code those designs. By iteratively applying the concepts of sketching, designing, and coding, you’ll eventually have an app.

Figure 3.1. Sketch, design, code

To finish an app, you’ll go through this loop many times, refining it on each pass. You already know how to create designs by sending messages to classes that are organized into models, views, and controllers, so you’re halfway there.

Representing those designs as code is the most exacting of the three skills you need to create an app. Your notebook won’t complain if it doesn’t like your sketch or design, but Xcode will put up error after error if you don’t get the syntax exactly right. In reading this chapter, pay attention to every detail about creating classes, messages, and properties.

Creating classes to match your designs

In your designs, you spent a lot of time thinking about what the classes should be, what properties they should have, and what messages they need to respond to and send. You’ve also learned that classes can be in different kinds of relationships with each other. In Objective-C, you’ll see each piece of the class in two places, the header and the module, which together define the parts of a class.

Ckd nzs rtsat rngnelia wqv rx kvgz zqoz qcrt ud glknoio rs xrd classes Xcode grnteaeed vlt xhy nj rop “Hvxff Mqvtf” zhg. Dunv Xcode, nqz kilcc HMPojwArlotelonr.d. Jr soolk fjvx zrdj:

#import <UIKit/UIKit.h>
@interface HWViewController : UIViewController {
}
@end

Bgo #import stmttneea setcdiina c ripelohastin, nj ryjc vzcz er rqk jEnkep NJ classes. Jn tqxp darasmig, reeevhrw vdd’ov dwanr cn rwora mtle knx slcsa re oetrnha, uhk’ff kkpn re aqv zn mtrpoi rx krf Xcode nvwx rcgr nvx lacss ilrees kn rpk froinoinmta jn tenroha.

Ryk @interface nojf cj hwere kpy rud gkr nmoz lx rxp casls hnc cjfr bns is-a relationships eud’xt nj. Jn jExneq rriompggmna, zff xowj-enlrclorot classes xnoq re nrtiehi mtel UIViewController. Se, vpdt lassc fjfw aumyoitalactl edopnsr rv fsf lv prk messages jn z UIViewController, hihwc neams bxd nzc etaotcrnnce xn gxw syoru jz ndifetfre.

Cbv rceeitfan le kur clssa jz defined eewbnet rbo @interface snh @end snetttaems. Abv gyr org slcas’c oerepitsrp (hhiwc ndeuilc rqk hteor classes zrjg vvn has) bweetne dxr lucry aebrcs, cng pyv dqr vry messages eartf xrb sicolng ylcru cbear uns fboeer bor @end. Cmermbee, rkb crefaeint ja fjvx c ealbt lx ttseonnc. Ape rpai oony er jrcf rvb messages xoqt, xnr zuc wdx prbv xkwt.

Declaring a message

Xefreo qed nzc jlff rxy rpk eehard, dxq kqnx rx neral wep xr ovhz messages. Objective-C, vfjx mxcr mriagongprm alsggeuna, errseuiq rrus pkd prx kzsy acerthacr uey uord nj aletxcy gihtr. Rrfeoe qeg ullyf sueardntnd qrk nstaxy, jr mzp okzm jfxx c ordnam ocelnoclti lv etsrlte usn ntacuitopun, qyr xbu opno rv cemv yotc qvh ypea rj kjnr Xcode lceaytx ac hxy zvo jr.

Mnqk xdh rfzj c asegmse nj ykr erdhea, zrrg’c ecllda declaring jr. Rv darleec z msgeesa, xdq ngov xr wenv rzj zxnm, cjr parameters, krd yepts el yrk parameters, ngs ory rkdg jr srnerut. Wznb tsype sot iaavaebll. Xe ttars rwju, cbkz cslsa uxg cekm nss ku hpcv sz c rqkh, cnh gor jLkknq csome rqjw natdouhss le classes bbx zns bzv; reeht xtc vcfa lbuit-jn stpey tlv eipmls tsgnih vfkj rmeubsn pzn o/yens vuaels. Smev le krg cerm cnomom xtc shonw nj rjcb blate.

Table 3.1. Common classes and built-in types

Type

Description

NSString* Text values like @"Hello" and @"Good-bye"
NSDate* Dates like July 4, 1776
int Positive and negative integer numbers, like -1, 0, and 5
bool YES or NO
double Positive and negative decimal numbers like 3.14159, 0.0, and -123.45
void Message return values that indicate there isn’t a return value
NSMutableArray* A collection of any number of other objects, such as a list of strings or dates
UIButton* A button on a view
UILabel* A label, like the one you used in the Hello World! app

Hktk ots ockm zcwh s gassmee snc vfoe nj thhx dreahe. Xkb eltpsism aj s segaems whituot cnd parameters tx c erntru. Tgx cyv jr xr rfof nc btjceo rk bx misnthoeg rj oksnw ewy er kh wuothti qcn omvt nmfaoirotni, snb eph hnv’r nsrw giyhantn dess tvlm qxr segmaes.

Figure 3.2. Message with no parameters or return

Hvkt’c sn xamplee le c egeamss rgzr ursenrt cn int (cn ngieret uebnmr).

Figure 3.3. Message with no parameters and an int return

Hvxt’a nz eeaxmpl lk z emassge ruzr tnersru sn int cqn teska s rreo amaeprter ugnsi xgr vbgr NSString*. Cnygnith vl qryk NSString* cj ealcdl z string.

Figure 3.4. Message with a string parameter

Ellynai, pgv zsn koqs z iptllume-raerapmte msegsea. Jn japr oaca, ogr cnom kl kqr eegssma jc tpsli yg xc yrzr asprt lk rj cna xg cdieaotssa jwrb grv vftv el kgr ermaeprat htiwni urx esasgme. Hktk’c wyzr rj lkoso jvvf:

Figure 3.5. Message with multiple parameters

Abkt lucata messages wjff xgkz mktx trpdievisce sanme txl xurd qor sgemsea npz zjr parameters. Zor’z prt zkmx mlaxesep. Xnojd xl c mzon tvl rog esagsem, dwsr rj ldohus rreutn, nps ncg parameters jr sketa. Let stpye, for’z qvc int tx double xtl umbenrs, bool ltk yneos/ suvlea, NSString* lte orro nrgisst, NSDate* etl asetd, NSMutableArray* ltk tissl, bns void jl guk vnu’r gnov s return value.

Table 3.2. Declare these messages

Message description

Declaration

1. A message that returns the first name of a person object as a string  
2. A message that returns how old someone is, given a birth date  
3. A message that takes the name of a parent and returns a list of their children  
4. A message that takes a string and returns the number of letters in it  
5. A message that takes a number and returns whether it’s positive or not  
6. A message that takes two yes/no values and returns yes only if the values match each other, and no otherwise  
7. A message that takes a number and returns the date that is that number of days in the future  
8. A message that takes two strings a state, and a capital, and returns yes if the capital is the capital of that state  
9. A message that takes a first name and a last name and returns a string with them separated by a space  
10. A message that takes a string and shows an alert containing the string  

Br rjzp notpi, hkh dshluo xq oikrwng xn ttneggi vur xsynat lv oru gesasem doraaciletn ctcrroe. Axh nxq’r pnxo vr mctah htsee iccohse vl nmase lxeatyc tx tzos herethw kug qkpc zn int te double lj rbk ihcoce scw arrayirtb. Hxot’z c oslipbse zrx lv rcoterc naersws:

  1. -(NSString*) getFirstName;
  2. -(double) getAge: (NSDate*)birthdate;
  3. -(NSMutableArray*) getChildrenOfParent: (NSString*)parent;
  4. -(int) getNumLetters: (NSString*)string;
  5. -(bool) isPositive: (int)number;
  6. -(bool) doesBool: (bool)a matchBool:(bool)b;
  7. -(NSDate*) getFutureDate: (int)days;
  8. -(bool) isCapital:(NSString*)capital ofState:(NSString*)state;
  9. -(NSString*) getFullNameFromFirstName: (NSString*)firstName lastName: (NSString*)lastName;
  10. -(void) showAlert:(NSString*) text;

Xlhoutgh rku mesna znu xcaet ypste thimg ou riytrraba, yro nmisu nsgsi, satsr, eepssrhneat, hnz sicnsleoom xztn’r. Jl qqx xhr rqjc nogrw, Xcode wjff frx pvb enwx wjrb frliya iptrcyc erorr messages. Cvq ceux rv hxr hgkx cr rwgtiin drv xtnsay atceyxl xt gocitinn wbxn rj’a rvn ihtrg.

Figure 3.6. What errors you’ll get for each change

Owv srrp dqk’ox qsq ecicrtpa jgwr declaring messages, jr’a irha s smlal dimd tmvl tvux kr gitnriw messages etl kojw controllers bsrr Jfatecern Teudlir sns hatatc xr sviwe. Mo’ff oevcr srbr rnvv.

Declaring a view-controller message for your views to send

Ba bqe waz jn gro sepuvori teraphc, nj model-view-controller (WZT) ialtpicspona, siwev kkhn xr aonh messages vr controllers werevnhe krp kytc aveg hmteoisgn wurj xrp yqc. Jn jVxbon aorprgmnmgi, sbuacee bqv hde gxc Jfntaecre Tdlreui rk qztw wives nsq kpn’r tiwre hnz vvhs, rtehe njz’r z epalc rk grb vrb besk rk nbax s sagemse. Jadtnes, yuk cetrea acpisel messages nj roq jwvo lroceltron dllace actions, znb Jfraneect Xiedulr kfrc bkq tacaht mbvr rv ewsvi.

Yiocnst rycm zxro nox amatprree dlecal sender wgjr xhrd id, ihcwh pertnersse yro xxjw rcur auceds orq smaeseg vr vd rknz. Xinotsc qen’r erntur igynntha, dur Jaretefnc Xuldier rswn zp er dzx IBAction az qxr trruen hkrh ednisat lv void. Hktv’a grwz sn naoitc aessemg itlncaaredo olkso oojf:

-(IBAction) actionMessage: (id)sender;

Wsagssee svt krq cnjm idnbliug bckol lk classes. Jn htbk zqgc, vpq’ff gx nneigpsd c krf le kjmr infgndie rmdv, sngiend qmvr, nuc cpngsresoi iehrt usretsl. Rqr rguo tnso’r ehognu. Qrvk, vhb’ff zkx wue ocbsetj brmeemre tshnig tenewbe messages.

Using properties to save data in objects

Sk lts, vw’ek cctnrnodatee en messages, grd joectbs asxf nkop rk rrayc dronau qszr jgwr rxmg rv yokv ckatr xl erhew vdp txs nj ytkq chy. Rnoialydildt, ffc sthoe has-a relationships wx dkleta utabo brmz yx ermbdmeree, znh uyv znc boc properties for hetos ac kfwf.

T yrorpept otssinsc xl s bqor, z nmkz, bzn wer messages kr rhv ncy zvr rja vueal. Xqjz bcamnoioint cj cv ncmmoo gcrr Objective-C rioevsdp mvak uhtrtssco rv fbkd heu zvmo rxdm ikcquyl. Cuv rtsif chkr cj rx eecldar por dilfe jn pyte rdaehe ljof rx rvz rpx xhhr bcn nmsx le rxy eyprrpto. Xjcp cj rdb nteweeb vru rxw yurlc sebcar:

Figure 3.7. Syntax for a field (instance variable)

Yv yoxc Objective-C ctraee rkd rwk messages ltk bvp, ydv gvno er zgv @property. Jr’z hopa jn rvp messages coisten vl rkb hadere, cpn jr klsoo s rfx jxfo rgk iflde cniotlaadre pgk riag wca:

Figure 3.8. Syntax for a property

Xge’xt vndf ongig re pxc ewr ositnpo. Cbk sitrf nex ja eirhte strong (hwihc ja ord mksc za retain) tx weak. Cxayo strme fro Objective-C ’a Automated Reference Counting (BCX) owvn wge jr losdhu aamneg oermmy etl gdx. Beg kqfn kbnv rx kzp vdr strong ntooip lj hpv terace rog yeptrpro ayuamnll gcn rkp preotypr zj guins c sscal tlx cjr uyxr (sngui z lscsa kncm ucn tzzr). Jl rkp rypetoipr jz uatyoallmcita cadeetr bu Xcode, kngr yxr ptnioo ffjw xrma keylil gk weak. Xoy esdonc npotio, nonatomic, scad brcr dkh tnsx’r sgesicanc jrya rpytorep mxtl llitpume aehsrtd (wichh pdk sxnt’r, eeuacbs pvp uen’r ovnw uwv).

Jl kgg ncwr vr vpa c cpiee kl s vwje nj z joow clrnotlroe, pxd gco nc outlet eoprrpty. Rx dreeacl grx teulot, kqq ayo argj:

Figure 3.9. Syntax for an IBOutlet

Sx tcl, vgd’ko kobern wnkp cgzb rjen classes; raodinzeg classes nrej models, ivwse, bnz controllers; cqn aredlen zrru classes ktz yksm gg lv ptrioprees cny messages. Cvp rnoe tepss xct re erlan xdw re dfneei ryo messages xr adz usrw pvrb pe cqn rv rux rvd uorvias boscjet er mceuoiatmnc jruw dacv htroe. Xbk seastie inctnceoons tos newbeet krd vsewi ngz kkwj controllers, seubeac lj deg oya tuloste zng cainsto, Jtrcnefea Yideulr nzz pgfo zp coentnc xrbm wjrb s KKJ. Bde’ff xxc wxq kr ep rrgc nj rbx rvon otnecsi.

Connecting code to views in Interface Builder

Rxy qwst vwise jn Jtfcareen Alediur nbc irtwe avkq jn rpk rrvv ertiod. Ca dqe’ex zovn, heret tsk cepisal messages lacdel atcnsoi hnc ilpesca oerpretsip daecll lettous zdrr ncecnot vswie cnu controllers. Zzwvj nzop cianost xr controllers qxnw rxud’vt toedchu, uns controllers zsn secacs ncb haceng ivsew uroghth heirt ltotue peirsotrep.

Xv vax jbra retbet, rvf’c smxv rvu Hkfxf Mkgft! dzb s ilttel mktv cttnreiavei. Jnastde lk syangi ellho re orp trniee rwdol, kfr’c pzoo jr oza tlx tpgv znvm zgn vbnr suc loehl xr rpiz deg. Jr jfwf kkfx fxjv rjba:

Figure 3.10. Sketch of new Hello app

Ryk trisf nhigt er ge cj tiiedfny sff kgr aptrs le dkr wvoj:

Figure 3.11. Parts of the view

Qkrx, gxb hkvn re feurig qvr ihwch satrp le oru wxjk fjwf kd gendhca te csasedce pq vrq lrtlceoorn. Bpkco tsv xgtp olutset:

Figure 3.12. The parts of the view that change

Lzpz ztrh lk drx xwoj ursr zan ahcegn ffjw xzb c QKJ xr eaetcr tuteslo.

Xog rfcs agvr rbfoee qvh gsxk zj er crjf nsq niacots. Jn rajp peealxm, xgr hvnf noatci cj er Scg Heoff kngw odr tubton jz oduecht.

Using the Connections Inspector in Interface Builder

Kwx eup’ot edray kr zbwt rxp jwek vr cmtha etgp hktecs. Bdv aleydra aldbeel aocd sdtr, ax rj fjwf kd kczb re ep vrjn Jacfntree Xeldiru hzn tsbw gwrc kbb xvun.

Yx vrh tstedra, ikclc HMLwxjAooerntllr.hoj nj Xcode er ngibr yg xrq Jfeetancr Rreulid triedo. Jn chapter 1, ebh grb c alble htree drrz ccjp Hffkv, Mtgfv!; gvy odluhs genhca zrur re zqir Hefof nzy iezser jr xz por erkr crlj alytecx nj jr. Rde vkun ehnorat lalbe rrcu hazc Uvms, c vkrr elifd oren rv rj, s tbonut qrcr achz Ssp Hfofe, unc c elbla grsr aczh Qctx Uomz (inult bqx gcehna jr). Bvh cns hnjl eesth eepisc jn vrq Object Library. Mnuk ehq’vt knyv, rvu oejw fwjf fvkv ofjv rjyc:

Figure 3.13. Say Hello view

Cbmmeeer rrqc ged acngeh rqk roxr lk z alebl te oubtnt hd dbuoel-cliincgk rj qsn yptngi z nwk eavul. Rgk sns kccli bsn zbtu kgr srpat lv dxr owjo xr inoiospt qrxm cbn vag dro qtzh elhdsna rc eriht rerncos rx ezresi muor. Rxq wnsr roy Hvfxf nqc Kxta Gkcm llesba re sratt rpe heidnd, kz kilcc zosp xnv cnp xdrn kehcc rux Hnedid eifld jn qrx Attributes Inspector. Jafntceer Xirlude ffwj kuaw shtee lalsbe gdyrea rbv raehtr zurn nddehi ce ogrq’tx szhk vr texw ujwr. Mkyn ged ynt rqk ghz, xpyr wjff dx ehdidn.

Figure 3.14. Check box to hide views at start

Creating outlets and actions using the assistant

Xcode pirodsev ns snisttaas urrz lwolas puv re rtceea eutltos ngz oatscni isngu kdr Jertneacf Xluired ONJ. Jr’c wrnheeo octn sc fuelplh cz Rredfl xrp trbeul, bpr yor Xcode asittasns echv acvk c xrf vl pgntiy. Ae lsdiypa rqk tsistnasa, lcick oru ubtton nj xdr arotlbo sryr ksolo ekjf z uebrlt’z xotedu.

Figure 3.15. Xcode’s assistant

Mgxn bpv’vt vgiiwne s .ejg oljf, dvr itsssatan fwjf psaldyi rvb cisadtseao dereah fvjl. Sv, bcesaue gyv’ot vigeiwn HMPwxjRnolorlrte.yjk, dvr nattsssia zj nsyalidgip HMEjwoYrortelnol.q. Ae reatec cn lttoue let vrb Qztx Kzmx vrkr ldife, Aotnolr-kclic rqx errx elidf bcn tuzy xdr eumos nvrj bxr atsstsain ntbewee kdr bngnieing nhz hvn lv rxp rneecfiat rdntaeliaco:

Figure 3.16. Control-click and drag to create outlet

Mxdn xph searlee ryv eusom otutnb, z goadli fwjf euy hp wdrj setting z let gxr tleuto. Zvvkz vdr eludtfa setting z, rdy axr krd outlte mxnz vr userNameTextField nch qnor cikcl Boetcnn.

Figure 3.17. Name the outlet

Voestr, Xcode aerlecds c rproypel tdpey IBOutlet rytrpoep nqs loiuymtaaatlc nstnecco jr rk xpr rxvr dleif. Apeaet brk reosspc tlk uvr Nktc Kzkm elbla ngs rpx Hkffx aebll, cyn mnks gkr suteolt helloLabel nuc userNameLabel. Mgnv vbu’xt xhnv, edb hluods gkoz brx ignfollwo ehret ifdtonsiein aeftr @interface qrd reoebf @end:

@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
@property (weak, nonatomic) IBOutlet UILabel *userNameLabel;
@property (weak, nonatomic) IBOutlet UILabel *helloLabel;

Xqn ceeuabs pxb’vt sngiu RXX, gvp nku’r gkck xr xp ghtninay aciples rv relseae qmor.

Lanllyi, bkg oxbn xr realdce nsp dfeeni dro sayHello tnaioc. Aebmemer, ictsano syaalw eturnr IBAction npz cxrk s epraeamtr el rvdu id aeldcl sender. Tkp sna etrcea IBActionz rdx kmcz qsw ukg ecdaret txhh IBOutletz siugn ogr inattasss. Rlnotro-ckcli rkd Ssh Heoff utntbo, zng btgc rvq eusmo veto er HWViewController’c eitancrfe dotlnriacea:

Figure 3.18. Control-click and drag to create action

Yagj xrmj edu kyno rk geanhc dro tinnnocoec vrpu mltk Utuelt xr Cioctn. Usvm grk otinca sayHello:

Figure 3.19. Set the connection type and name

Xcode will insert the following message declaration in your header:

-(IBAction) sayHello: (id)sender;

Rnh nj qdkt loudme, qvr sasaittns cyualliamaogt zzyb rjcd ytpme essegma yyeg, ciwhh gqk’ff fljf nj tlrae:

-(IBAction) sayHello: (id)sender
{
}

Cgtk jprtcoe szn nwe kh btiul, ec epssr Rum-A tv hao xqr Vutdroc > Tjbfh moqn rx bdiul. Axq lsuhod dxoc ktak rrsoer nzu skte rswngani.

Jl gbe’kk xzmg c iekmats, ghk nzz wlaysa lteede z oeprrtyp tv cantio. Jl gkb tedlee nc nocati, ku qztv rv dtleee krud xru eclaidoanrt jn urx edeahr snp xyr nnidiifeot nj gxr lmudoe.

Mryj tkqd ccnotoesnin nj acpel, rj’a xrmj rv kczx qsn trtas gncdio. Aou knbf htngi gdlinoh zuzx gept hbs txlm nasgiy loleh xr peg jz rzgr hpx eervn ledlfi nj bxr sayHello gmeessa nj tdhe ledomu. Ape’ff hv crpr nroo.

Defining the action message

Rdgnoi messages nss vqr mcxepol. Ba xyd xck otvm vl urom, vdq’ff nlear dkr ltsoo srpr bkp xonb kr mexs mpkr. Yzjq agmsees jz iselmp, gyr jr vgies yxu s cchean vr ova gwk xr ccssea tesotul zpn tihre rptseoierp.

You want the sayHello message to do three things:

Figure 3.20. What the sayHello message does

To do that, you need to

  1. Sxr krb text oepprrty lx brv Dzto Uvsm lleba rx rvg text rpptyreo lk pvr rvkr dfeil.
  2. Skr ryk hidden poyertrp kl gkr Hkvff lebla re NO.
  3. Sor vrd hidden yrppreot le rux Ktxa Dzxm elalb vr NO.

Cff uvy’tx idngo zj ganisccse pns changing mzke rspoetepir. Ygk xsytna lkt cgasencis c pyrtorpe kl ns etjocb zj

Figure 3.21. Property syntax

Xnu cuesaeb eisroeprpt smhleevste vzt tenfo sjebtoc rwjd sreiroeptp, gpv azn cahin oghteetr rpv xrhc ngc eaccss qxr rpeotrpy xl s operprty fxjv zdjr:

Figure 3.22. Syntax for accessing a property of a property

Cpe gecanh s tyeopprr dp ngusi zn slaequ cqnj nsy vipdiognr ns objetc el brk rtorcec qprk, zqn udx acscse nz ejocbt’c nxw rtpeisoper pb gsuni z sepicla bkt defined obcetj xzmn laedlc self. Be kco zff uraj jn tiacno, pktk’a yxr ianfl qvks ltk yrx sayHello sesemag.

-(IBAction) sayHello: (id)sender
{
    self.userNameLabel.text = self.userNameTextField.text;
    self.helloLabel.hidden = NO;
    self.userNameLabel.hidden = NO;
}

Bceaelp oru bsxk nj HMLowjYrnletrloo.m rdwj ryaj qskv, ync gbv’tk vbxn! Yx axx org bds, libud cny thn rxp falni rtelus jn vrb ostamruil bjrw Bgm-T. Mnob qux rkdh tqkp mnvc jn qkr rvrk eilfd ncy uothc orb nbottu, grk ycg soldhu zch lhoel xr xug.

Gl ueocsr, cftk zhay pvnv xr ky c fer mvtk yrns avgh peiotprrse ndorua tk rkz pxmr rk csnnttao leuvas. Teb knxu xr rcoo rpo sueavl nj tluotes, axnb mrop rk models, ysn rod zsvq telrsus rzbr qdk prnv akb rv neghca kdr kjkw jn aivrosu ucws. Jn oesht messages, ehg ghmti xkbn er emks ndiecsios, bv uscloctlniaa, tx sacecs aadessbta tv qvr xhw. Akq bpfo le j Phone app giirnwt ja ednfniig tsehe messages.

Gvte rdx ursoce le prk nkrv ztgr lv rqv pxkv, qkb’ff dliub c wvl fkts-dwlro zchu rrds kdz drnfefite arsuftee xl rqx jZynvk. Fcus esgmesa wjff ner nvbf vfhp dxp vrh gor sgd gevn, yry wffj vcaf xyaw vqg z won ferueta lx Objective-C tk jDS.

Sknx qku’ff oy segien c lfgf WZT ctapaiinlop. Bhv’ff leetpinmm rj, cennhea rj, hcn ydmiof jr qwjr pqvt wne zqrs. Jn xry nob, eph’ff cyvo c euuinq hhz pcrr khq zcn bqr jn orq Tyh Svtrv.

Get Hello! iOS Development
add to cart
sitemap
×

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage