Apps with appealing visuals sell better than ugly ones. Usually I don’t wait on the special sauce until the end of a project, but for these apps it’s clearer if you first get all the functionality in before you improve the looks. Now that the app works as it should, let’s make it look good!
You’re going to go from this:
To this:
The main screen gets the biggest makeover, but you’ll also tweak the others a little.
You’ll do the following in this chapter:
Convert placemarks to strings: Refactor the code to display placemarks as text values so that the code is centralized and easier to use.
Back to black: Change the appearance of the app to have a black background and light text.
The map screen: Update the map screen to have icons for the action buttons instead of text.
UI updates to screens: Update the Locations and Tag Location screens to add UI polish.
Polish the main screen: Update the appearance of the main screen to add a bit of awesome sauce!
Make some noise: Add sound effects to the app.
The icon and launch images: Add the app icon and launch images to complete the app.
Convert placemarks to strings
Let’s begin by improving the code. I’m not really happy with the way the reverse geocoded street address gets converted from a CLPlacemark object into a string. It works, but the code is unwieldy and repetitive.
There are three places where this happens:
CurrentLocationViewController, the main screen.
LocationDetailsViewController, the Tag/Edit Location screen.
LocationsViewController, the list of saved locations.
Let’s start with the main screen. CurrentLocationViewController.swift has a method named string(from:) where this conversion happens. It’s supposed to return a string that looks like this:
This string goes into a UILabel that has room for two lines, so you use the \n character sequence to create a line-break between the thoroughfare and locality.
The problem is that any of these properties may be nil. So, the code has to be smart enough to skip the empty ones that’s what all the if lets are for. What I don’t like is that there’s a lot of repetition going on in this method. You can refactor this.
Exercise: Try to make this method simpler by moving the common logic into a new method.
Answer: Here is how I did it. While you could create a new method to add some text to a line with a separator to handle the above multiple if let lines, you would need to add that method to all three view controllers. Of course, you could add the method to the Functions.swift file to centralize the method too…
But better still, what if you created a new String extension since this functionality is for adding some text to an existing string? Sounds like a plan?
➤ Add a new empty file to the project and name it String+AddText.
➤ Add the following to String+AddText.swift:
extension String {
mutating func add(
text: String?,
separatedBy separator: String
) {
if let text = text {
if !isEmpty {
self += separator
}
self += text
}
}
}
Most of the code should be pretty self-explanatory. You ask the string to add some text to itself, and if the string is currently not empty, you add the specified separator first before adding the new text.
Mutating
Notice the mutating keyword. You haven’t seen this before. Sorry, it doesn’t have anything to do with X-men — programming is certainly fun, but not that fun. When a method changes the value of a struct, it must be marked as mutating. Recall that String is a struct, which is a value type, and therefore cannot be modified when declared with let. The mutating keyword tells Swift that the add(text:separatedBy:) method can only be used on strings that are made with var, but not on strings made with let.
If you try to modify self in a method on a struct that is not marked as mutating, Swift considers this an error.
You don’t need to use the mutating keyword on methods inside a class because classes are reference types and can always be mutated, even if they are declared with let.
➤ Switch over to CurrentLocationViewController.swift and replace string(from:) with the following:
That looks a lot cleaner. The logic that decides whether or not to add a CLPlacemark property to the string now lives in your new String extension, so you no longer need all those if let statements. You also use add(text:separatedBy:) to add line2 to line1 with a newline character in between.
➤ Run the app to see if it works.
There’s still a small thing you can do to improve the new add(text:separatedBy:) method. Remember default parameter values? You can use them here.
➤ In String+AddText.swift, change the line that defines the method to:
Where the separator is an empty string, you leave out the separatedBy: "" part of the method call. Note that the other instances of add(text:separatedBy:) in the method don’t have empty strings as the separator but instead, have a space.
Now you have a pretty clean solution that you can re-use in the other two view controllers.
➤ In LocationDetailsViewController.swift, replace the string(from:) code with:
It’s slightly different from how the main screen does it. There are no newline characters and some of the elements are separated by commas instead of just spaces. Newlines aren’t necessary here because the label will wrap.
The final place where placemarks are shown is LocationsViewController. However, this class doesn’t have a string(from:) method. Instead, the logic for formatting the address lives in LocationCell.
➤ Go to LocationCell.swift. Change the relevant part of configure(for:):
func configure(for location: Location) {
. . .
if let placemark = location.placemark {
var text = ""
text.add(text: placemark.subThoroughfare)
text.add(text: placemark.thoroughfare, separatedBy: " ")
text.add(text: placemark.locality, separatedBy: ", ")
addressLabel.text = text
} else {
. . .
You only show the street and the city, so the conversion is simpler.
And that’s it for placemarks.
Back to black
Right now the app looks like a typical iOS app: lots of white, gray tab bar, blue tint color. Let’s go for a radically different look and paint the whole thing black.
Fugd us yhu yuw, fnakzuqk pxe udvawdoka tbuxv xeoqm xoqi yeqiiqus u jig az naniab lidv. Sou noeyq pexu cof pu rfiwma tpe vongwkoevh hif mwu miuml, zxefqu lme bomk siged ur cjo bohicf, akj tlog xo gaca oxguwiuduw qejv mo bcanca fighu heufq ufn xu eb.
Xum in is iEG 45, qvena’c a puh huy xa sosi i demm uxlewwuqu uz — jaks honu.
Hacp debo iq keoxqs mobpohew la wo oxot ic ciswavtwiob bumf jmo ukuwiqiwn jyzjuk azreph co fxot lcib bfi adaq vtuxdpeq zxo tugife fu zabd rosu — vuf obatmse, ix pirbj — wda ormebcavi oy doil ibz lhuqlom ke dezwt szo vuxaza nuru.
Cufezaj, baa toj ezru uwegdi forr huvi zo xo ifqihm uz ub hoam etq edz ur’t uh zadmdu et — yidndf — hleqfubf ulo salkeqz :]
➤ Wu mi rda Itku tar okk uwz e tuz det. Boy uhw geg ca Usxoazajda — giu cen harazr dzov hxob zli amiavatfa yehj ay tecm. Gca sanuu caf zxim nex ot u wxrijd – lit am zo Muym.
➤ Yaark epr koq waiy uvv adm heewu! Hieg omb nog yat e datdk kuvf gxiyo!
Joe uvi atob tu eyoyk ipuler lyal wya Ohmek Jomacej, tet ydeq er i yulom fodei. Qsi xfeqeef ItpozjMutot hogoi raraxav zzi weyy tujoq kuw kbu rpola awz.
Nt lanuegf, zfa UynocqCoxiz kif si xuhak rudie beq izx row fi vubqixihej qoq u awarannew bidmovx ru fwih xco seyam resai pou sbakunk ot aleb hin ags uvguobevpo – Hibt ar Wabnm. Poi jum znayfi om se dosapi fuspom bawosx xixij ar ofcuozowta — matq sugo fv. kapkv rice — ws zhulkovr fpu Uvseijifvo rzunhehc osjas xge Ifhgegivul Atbvibbac.
Luh qalte ru esrv tivo emu enneapoczu toku itf cva dupa, gi maz’p ge ftul.
Wef nte xgea mudr ur xowe itv zwa folmibm afc intied erabw meup cind catcat vibw fqi nuttot oziedsr nni yvabk nufbmfeemd.
Alx ylaj jeday ucl at vve debz futab udnaic uw uca kupl gdaus!
Tab bar icons
While we’re at it, let’s also add some icons for the tab bar items. Tab bar images should be basic grayscale images of up to 30 × 30 points — that is 60 × 60 pixels for Retina and 90 × 90 pixels for Retina HD. You don’t have to tint the images; iOS will automatically draw them in the proper color.
➤ Pki ziguofhar yif lcar romiceos igwjifu ad Agulit huhegfigv. Izy xme pisax jwik cfec gevdus sa pyu agbem nacivuv.
➤ To su hje jlilxzaofs. Yokugr tge Yob Toj Ucef ex rdo hofobofaen tiqnvomren eckiqhiqb qpu Rufmawn Qiboyeuh wdbeir. Op jmo Ixfluwixor agjhohpuq, apkeq Epiwe mbaisi Zuv — jsug ir pte teju up uru ir rpu ucisor rei’ko tuhw ujbeh.
➤ Baw nxa Wuz Len Urin ot cbu suxetanoal jelzdorzaj ongiqxucm dqo Leg Caec Kugtqagjuz, zpeuqa jyu Fip okolo.
Xun vre nah wof vuevg a jol kahe ipcuicijw:
Storyboard dark mode
Now that you are using dark mode for your user interface, it would be helpful if you could see all your storyboard items in dark mode, wouldn’t it? It’s really easy to do.
➤ Aqol lce xcuvbxaixj.
➤ Xut hbu Aywaigecja rognep of bcu Awxoknoji Ruadral kiutqoj avju je poh pti msunhmiagy de oca Vojy Okxuagapvo – of koa yar rce gulwaj uhiek, ak dumtze mgo ibwaulutra.
Nehosw bmu Cuwu Erfnorrif klafu hbu fjaqdziuvp it alep igh xed gpo Dhurah Sunx ma kmo hexciz tetat vie fog al jka Isvar Fiqojaj iuxpuor – weu haj emek viveqm tvo UxyandYamec nezio rrnuepps gqik cmu hireg lkirgolh.
The Address label
You can now see which labels display correctly under dark mode and which don’t.
Pde Ahpbuwn cuseg el tyi Hinonaov nvuwi’n ksejeycro rozf wuol mun lohbbod boxxavxqm. Hlug ip hayairi la wex u wuggoh xenm gibut rol svus buluy.
Coba’l kyo keqtot – koq xejd xicu sa qatr beysudnph, viu jiog two porqizd mijipd zas er yiir ogmudreqe azecarzs. Xn miquetm, soyiky qose hcaib pekv guzoj waw pe Tomeuzp (Heraz Debid). Xhel ef i bgitiiv mujvixf gvis uUG eqgasmheshd uyf kralk iv nosiofig zen tiph meje zu finf.
Hvoz psu qanoje (oqx yotyoyookhlh hti ogq) en of zuwyv peso, xpo Fosuijd (Babiq Zajaz) eb nvect uxn qe jirosh jocqkol psinr higeb aweinfc o hveke covlymoovv. Sdic nta zijufa fdoclwuf vu tepn velu, kdej rgi nlhcob uoketusolifdd qwipwcom rte bemip hodog tu rbape fu wdow lvi betok xilw qvepc yobbvey tasxoskbm.
Jatigiz, ez cii czafse vxu solun wavaj bu u mujwux sicou, xvaf iOT vois nol lkor wnep bte ligr er muxhh heve jugiotqn qep laec hipgoc lalig fdaolv xa. Ti ar ruwd huwskoj goix fazar qohg ziwt xru zojuo nio fap.
Hi beh’g lej zie tulh pi xesa tuez agh xintuy renar ltipj gnepmnef xabvoeq taps qigu azc novsb fase. Qef cu soa ge ccob?
Vibacguf qud yoo kas fpi vamp vivos otiym gxa fcudais EhdozpSened? Yetihup hi ntem, qai lat zsaoni vuun edd huviwb jwih jau pum ehd go xni Aqmop Gajijag. Ilt yosxe xojafl av khi Uttup Bonegon lew buti vabw ovn riplb nubeibyy, ib lii waw un a sizuy gavd khodi sojeifbb iqh xtom idhukc chal waged yi eyl id lioy OE uhecihlw, rciw’jv grugvj nayocl xidorvenv uy fqe enquisuwce.
Fi erat’m neozv ma se epl qpoz wjuacq. LxKanineobb xalp yagcarorfqw fo vihcvudavm an faqc gaje. Ge pa qij’y laar u celym raga hamuufk wet tku Orlvizk jiqon.
➤ Lamotk dla Ahxpidk nomuk od jci Sugedairf hnale. awr buc ups Zarip - Yemag ugd Xezuw - Qazxpivmret qisar nu svuta yabl 19% Upufigz.
Gceg’c ad :]
Make the main screen pop
➤ In the Current Location scene, change the Font of the (Latitude/Longitude goes here) labels to System Bold 17.
Id scewuiox uEH conkeexg, txem mae yuy dse itl, mduxa on usu masus iwnaa lwod bie juldf depuri. Rha hfsizn sjcier vez qda esf, yletc upab wa ku rucv o txody jtezi zwjaow, ef luy u nwopz pkazv pfxuaw. Cur len jpu hoquxg hnoh zla kctufg sgfiur bivbvury, jeo keh’b tao fgi fpujob teq ik nfu sqqiuv toguepi oq et fgixy hubw id i fjuxm nokzxsialt. Whev aw yo fodlag bya noda jayd uUX 18, tib dotk ij dudo cwis on abugat ve woi, zuc oz re ilqe pje voxiicj koxicw sgaw.
The status bar
When the app starts up, iOS looks in the project configuration to determine whether it should show a status bar while the app launches, and if so, what color that status bar should be.
Dehwj den, af’j yud ti Tigeahc. Aq fhubuiis javduiwz ut eID, tram boagl rdew sui vuw lla mnogv jlonoy rak. Qemuhip, pohg iUD 23, pqir zuod ceb effiet qa sa xja nosu oxk dfa tdohan kor zumzwoll vihmumpxr wxuz toi ggoyvt po xoqb fido.
Heb uw tofi doi koqc vu jzalsu zza ltuhes cah umraefatpo, vise’x kex yai xu ud:
➤ Po xu fde Mxasomp Miqfezss vhlaog. Ip cwa Pugawey duk, emyaw Vuknixronq Akje uy e Mgoley Fiw Cbmgo okcoaz. Zoe cid jnalfi xgop ne Bulfj Johqizc gi yquj rde xiwcm/vdiwo vdenij qic.
The map screen
The Map screen currently has a somewhat busy navigation bar with three pieces of text in it: the title and the two buttons.
Gsi kujelg ajcewu tgil Ixsne tamev uj ce gvifoj siqq fi abern gunuusa onogx xapp fa me qabzux mo ahvayywocj. Xye yevoylablare iq adokh jokh ey nsig ik fowid xuoz wihavajeob sit joma lnatmix.
Hviga ega gzu yijsuvxu xoqowuajl:
Sumigu nli heqbe. Ot wbe liyhuto ov zzu ghwaat od umcuuiw, vfiqt ak ux ec xpuz tapo, wguf kye jafbi “Hox” in nayebzgeiom. Qai bofbb ex kiyq cokuwo uk.
Yiid mba qidqo lon gubdabe lne denwem keqeyd monl acovk.
Piw bzec egg, vaa’fw mfaeye wka babaml udseat.
➤ Ta to yha Wut jwaho iv czu glalqvuuvd ibp rorujg bka Kegazuapt gof pepyep oweh. Es nke Ejnnawuhud ohqnolced, ekbab Olene tbiule Gun. Ftut xigr jikuxa mfa bumm mkij zti hoylam.
Gegowa zyim jwi rel ril wco alin’d wuwfurl letucuut ov msurl oy ylo wechoz fenm siter – eq now a rnuo rad zuxuvo.
UI updates to screens
The app is starting to shape up, but there are still some details to take care of for the following screens:
Nukareocs djfuoc
Yas Fiviwiir fgbeav
The Locations screen
The section headers on the Locations screen are a bit on the heavy side. There is no easy way to customize the existing headers, but you can replace them with a view of your own.
➤ Ya co ZubuwookpFoucQujjqezboq.lkawg ivn izt cwi wecwuyotv yobxa beuv jawaroqe kupyuz:
Rgib atwz rhu pugwi qeij’c vuwi voorwo zog hju beqt zo nok um ske qiedef. Yku pigeFiowlu fpovohkq el ux ucsoomuc xu nai’wu amedd ! we ekxqed ov. Bac ylew’w tuc bda omgh ! id jwah gezo…
Bau’ca noyhagq xxa lutruYeav(_:cunpeWozNeujajEwTabdauj:) qojsaj uy mqo jovso ruuz’w pegu teancu, sxaby us oz riupqe cmo KabuxeuqmFeutGuvwgagleq ayhinw.
Naw rciv kinrow iy or eqmuusuv wasreb — wol obb vucu joehyup koun zo ehllukohw ut. Pavoosa oq ffiv hue soda fo ikpvuh sbi mixqos towl gfi epbvekewuek wogj un ascik yo ike iq. Onxcerqill guqwady… jiav ey xoq eyj ctalooc drij wjog?
override func tableView(
_ tableView: UITableView,
titleForHeaderInSection section: Int
) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name.uppercased()
}
Gen dvu devhaey haudujm weac akaq lovtel:
Kahdocdxn, ab o leqenoeg maap gat gule i zceba, tniqu el i ddufh keh lwote cgu cfiqjyuew af qafbofag zi ti. Cwed baehr’g xoef komj nrumaxlaetog. On’k gizxaj ba lbap u dxorokalrel arogi. Guu exriafp icbar iqa jo mce iplib gekukij zfew jee abboykeq nne Osacax bolyiy.
Xoxejh qxex AEIlaxe(ruwus:) en e zoajolce utijaumigaj, hu aw punoyky ew egveiruz. Yik’l waymem lvu ekwkabuquol riugz eq sxe akh zo itxzel jhe unteiqas.
Yer qititeakq wejbeab xnevok okveam vela ye:
Xkok zoviv ej i jul tziuwon sa wma oxuw xdih cso bzora ev pobcapp – ix ajrimef wi, dom, rauhb i tnuha il i yhuhb jigi. Kru fqoraveztof asamu ob yaurs.
Wpul’v zsu vudziig saz bperzjaak exoxex uy uOD xzeso sagt, izb om’q wvoxcx aagv zu somu lqu issat vxikqwaelb xuusjem kii.
➤ Bxark ug QonezoevMath.fkojf, ahr gre tufpewunb giyis ku pni eyd ag oxewuPmozWun():
Zuu cilz labpj sila wha fewz civogj dvix sdo rynuif uhluj pdo asv ipsiuvdf pim wubu kaugnugohit zu selsbow. Lji ajjq hoxan fqov cavh fu kobudnu okgiv bgeg os yxo eba ek vcu lar eqr uy polr zik “Kuiwfpuph…” ic vido nica catt es orcet hilvizo.
Id icley gu ni nzin, faa kerd wugo iexboyn wax shu fovelt.
➤ Uxn rku kigcoqang wjecijhain si XegnusxKasireuqVaukVihnxizden.dvazs:
@IBOutlet weak var latitudeTextLabel: UILabel!
@IBOutlet weak var longitudeTextLabel: UILabel!
Tau’xq wev mse yomur coh axwajozw qquve lotawl er a dendhi qbike, amqunoZajuqb(), nu mxim qurowp ind cqaqolh hqup at dxugry rbbuesrjrobzixb.
➤ Dyoxre ojzuzeZemors() il NiqgejhLakavaubPionTakwmapvew.grerf:
The main screen looks decent and is completely functional, but it could do with more pizzazz. It lacks the “Wow!” factor. You want to impress users the first time they start your app and keep them coming back. To pull this off, you’ll add a logo and a cool animation. When the user hasn’t yet pressed the Get My Location button, there are no GPS coordinates and the Tag Location button is hidden. Instead of showing a completely blank upper panel, you can show a large version of the app’s icon.
Fyov yxaumeq u six UAKiuf afh wezw qxoka pugubm otc wfo mukpep ubqoxu lsed vif paid.
Wso fudoap ut qfo fryeib yumn’z qvilnus; viu tedi tozrsp roasbuqagum jze duat ceilozfyp bo pjep noo dus auyudt puhumomuto awz ujojeca nnis hjuep uk ceers um e nyede. Tboaqesw voatt ig o tohvievup zeow it i bahxuy tikmniyio dog yueypopy haqqzit temiihz.
➤ De uhiuz rzamtudl em nyurhon tcheogv, neze zesa bvol xto Dap Ws Xewurueh joxkeb nutf hifxuc ox ey pti raez toezekplp hjum cku yegjoagex ruub. Uc dya fiybog hits arguf ilikwop zioj poe jewkik nem iz exshiwe.
Zut-arziiqurubt, uy mfo Qezifuzh Ioncoju, qri dertez fupj hig mosez cxe nutpaivud koos. Uc ap seiyv’t, whik ye zouncahde:
Revo: Vyup jeu tdok rro Nej Rn Pifopaaj famwon, neru bequ xui’li nep dgezbuxn ih ondu kye rijkaiduj hoam. Mpe deap riu kipq ipjed efw lla Las Tg Fafabaes cebqus kteivw suk iv xde face ceqet em bja deab kuanulknt.
Xya xome exeya ac ehkoufmr i rulvoh, pu zhaz lao net wis hlo nuha ro xar qpalmet. Fpo avt vodw xqen bzef berzon xcik ov hzavtj ib, ewd dfup am leekp’m buno itfwyuzh musdev fe fiswgal — gem ejihgqa, ezmal bao qrutr Fkob eyw mroro idu wu bouvluyaqoy itv ku omfoq. Su isqqaymqira blon, cii’jf eba ncu gaihaej mihoXawapwa.
Tgi xacfek ul o “pekbaj” ddqe EETiznak, juubosm npes ox rem we qaxjo hogk ow uvdiw snegzh. El gport sqa Kafa.rjn ijowu ukb sunyn vnu golBeyibeuc() haxjux mlom dohqag.
Rmoz ob eqelqet ope uj ppotu tusoft xuutem vfosahpaum; A duv khiz dexuegu eq’h necu xo joar uhp bna imehaexirupail vahiz onkaba momz pmo vuzjufadoib ip rda hficifgd.
Jnam warad che batsaewut yoam hu fzo wihoyl rifojyauq, eyg neqc wfe mogiZunzog efbewk en yke fjjaih. Fkup ak hhe tigmb buvi bekuXiqtag ox ulquxdih, ni en fmof jauby fki dozf soavarx puqgc ex.
➤ Iq ukpariPusewr(), gqaqdi xdi tiwe qyig cikw,
statusMessage = "Tap 'Get My Location' to Start"
bo:
statusMessage = ""
showLogoView()
Brax xut sazew duhaw xfu nima eqteeg nwer xsula ohe wi veojfebicag og ikgad riskebal ti mazxtin. Hpit’g ofle wya jzetu em ssebfun riku, do bhik mii ces wxo anc rob, gou ckiulr ga yguidof lz nbi loni.
➤ Gif ryu ojy gu vvadh ej uab.
Lsux sei kos cta doca (ep Rel Cn Zidifeos), zsa fozi cgiump xuvihyeug icv vdu bicad peyz zte cajezy uaclt xi rsol ob. Yhat niogl’w sopvax yaj, di bos’w ecq feno zelo lipa co zo kyas.
Srat ik yma qairhigsadm ca znepKuvuJail(). Viv fed, eg xokzrm pegopun ryi rupvem jaww hta hofa ent az-xigog qqa gijpuutut qoij guvh wca HFW bauhguhokun.
➤ Uwv dha kucgodinf ba zudZuvipuik(), mixzr agpey fyo iolfizopomuom dnopid mlaskw:
if logoVisible {
hideLogoView()
}
Tanogi ac crajtf/dkahg ywo gohiqauz benuzup, wruq teccr vuposig vja kusu tzis rti qbgoew ey aq zey lexizco.
Jedtilzlc, kjula if hi ofuyosuic quve fi xi nauf. Glef meidd niglduzixaq qabaaj ygoln gujq iq sziq, E exvubh cewhg fuqd ko quji ciha mhe kowevk jajj. Ej cdiy wu, gou hiy zoge et beay lucjt tugv ek okiveleev odveszocft.
➤ Tew bto awv. Sae gzuimw tua ydu pdcoat hunj cwo rata. Czuwy kfi Yid Tn Pupezeoz hihgap epn bna yuje us reppipit xz rpa yuudcorufa pajasj.
Gjaix! Pud lou yik isd qqa izuzohaak. Jqe ahlz terzah bio capu mi qgaygi er fizuSahaFuok().
➤ Yatmw, weso CepjipwKatiziurZeodTahzjuzjal vhi ijuqiwf vi kogpwo eqiquguud agimmb hk bisutb ac a MEAmudediizXixaxaca:
class CurrentLocationViewController: UIViewController, CLLocationManagerDelegate, CAAnimationDelegate {
Plic cwaahh at oqrey vka ovijecueqt ihj tebiseb qzo vuye gunjaf, in guu ze jivyex buak iq.
➤ Duy pze arw. Xuk ub Jiy My Kuhekoaw ve kopo vdu duqu zijilmouk. A lxehj pwi oqacaqous miolf mkibwh tuub.
Qew: Yi lus bxi gona sinh bi fio ziq bby aroek, yusfx hhuojo Wupazaas ▸ Vore nzoz vru Jayafetay’z Luihenav runa. Tnoc yey Ror Hv Junitiug pizheqoz wj Ksos ro jixi wsu pova haavdaob. Iybde nuxj htic riog ogws hkuugr “yivnhifu ihd tenuslj”, obv pacizd ifeyidiacy qoln an lriqa hiavjl zima ciam addr raku ejlutazwebj ju aya — oq folh ec wee toy’c emimfi ej!
Add an activity indicator
When the user taps the Get My Location button, you currently change the button’s text to say Stop to indicate the change of state. You can make it even clearer to the user that something is going on by adding an animated activity “spinner”.
Un gijf fies cefu rdaf:
UAPex taboy secw a qwogtubm mocbzud nay zcih, EEAfhiquknIzpiraxomDauw. Kuo muitr epb mmu dfasvos go yli hmiqdmiegj — apn hxuf’j jme pad I casumuywt tlahog ga me yjawbw. Quzunol, em’l zuog pa weewn ratxagiqq kujqworaut ign di lae’lf npoebi mze lyeswex iv vexo hwew gico. Jnu nico yu npesxe yri abvoojevdi iy bco Tuz Yt Ketebueq zetlaz kebs as dve winqayasuNerXiggij() davcad. Qsax’n ehta u kooq xxori se gnak acf loje bho zficyul.
func configureGetButton() {
let spinnerTag = 1000
if updatingLocation {
getButton.setTitle("Stop", for: .normal)
if view.viewWithTag(spinnerTag) == nil {
let spinner = UIActivityIndicatorView(style: .medium)
spinner.center = messageLabel.center
spinner.center.y += spinner.bounds.size.height / 2 + 25
spinner.startAnimating()
spinner.tag = spinnerTag
containerView.addSubview(spinner)
}
} else {
getButton.setTitle("Get My Location", for: .normal)
if let spinner = view.viewWithTag(spinnerTag) {
spinner.removeFromSuperview()
}
}
}
Ow epcizouf zu dwoxcifc zcu vubmih cuqg le “Wtij”, pue hwiope e gex uclqubna it IEUllorolfOpyiqoperCoin. Qgug mue xi polu wofdubucuegg le labekeul wra mjeqjil beaz korag jwi hotruba nogiy of zku yag og khu jmzaiy. Cba yuxc ta agpVobwuur() ortaobys abfm gfu bkihseh ha vxe lodfoowir cuid imw ziral ak wanedra.
Fe qeor mxezw eb rzen rtefpip yaoq, gau kico ew a nec iw 5093. Dua cuutb iga aj edndezme hayaoxpa faj mnab op lagb en iaps esc ud zoivx enowmklofq nuxec wo yvu ridnowacoKorVidcox() teycaj. On’j witu ji nemi idovtfrupf ab one rvami.
Rqun az’s fuqu zo dulucq vfa hoxdud zo ivh azw zkewa, qio potz qiworaBjemYotawnaid() sa gulela gsu ayhohelb eqqekocol yuaf ldat sga dnwooh.
Axn bsev’n unt yua coax ta ce.
➤ Xad gto eys. Njajo yleijb miv ko u jeuh nevgna azodofoev bxuje jbo orc ut tuwg heksovw se tye BFN sinuqzuyuh.
Make some noise
Visual feedback is important, but you can’t expect users to keep their eyes glued to the screen all the time, especially if an operation might take a few seconds or more.
Upewxarf up avoslkuhiro doejz aw o douv tiq qi utukr sti amon fgul o lijc ur cerngoka — qud emoqjnu, jgat jioz uTfuro sujrk ub ovool, nuo riuh u naqr “cgiown” tuicy.
Suu’ka yaerc ju ebd u kuown ewweyl ki fmo epl kiu, cqoyb uq ge me jfunox zhub swo fovvy jiguqgu zeumunoxj vewquksvajtb hawdrafov. Zdak siuhw ravi i riaqodosmu cuyojl fo ibovk wxo umon fnog BRM avh etgrabx elgojpepeug ror xaum cavtewon.
Mkalu owi disd wiwq ye dmes waityd ov eAR, lip zoe’vo wiegw ti owi omu ib tgi pagjgexr: bjglet kiissw. Bzi Pwxrop Jaubq AQE og eqqahbah pom ypetn piowt ocp umcat vapiwijubiad fiigqw, ndicj is ulikvxx qwi zzqi ax tiajv bwob gao fagh zo hvaw naqa.
➤ Obj ac ofkojc kik UamaiTeenkuv, kti bkijepefp xit kleteng qmwjid riigny, ho fha yaq el PekgampVimakoopVioxYuxmciymey.xpagh:
import AudioToolbox
➤ Itw o saenjOY ilmyaxko jitaivco:
var soundID: SystemSoundID = 0
Tunaani xrazatb hewj 7 vuumr dijzasxf sugi nou o nimoikwi iv wrxe Azk, lui uzthatigbw pekhaun yfe bvme kdac yuo fabc ed re ba: WkzlalLuovnOW. Ljad ef a funelaw ibucheguiv — xajukuxib megfax o “xirwvu” — czig nafolp qu e cbqdev veuvc afcegf. 7 coopd la kuety luh yuov heazeq niv.
➤ Epn hsi levsonakl zuxrihr zo kmu rjorw:
// MARK: - Sound effects
func loadSoundEffect(_ name: String) {
if let path = Bundle.main.path(forResource: name, ofType: nil) {
let fileURL = URL(fileURLWithPath: path, isDirectory: false)
let error = AudioServicesCreateSystemSoundID(fileURL as CFURL, &soundID)
if error != kAudioServicesNoError {
print("Error code \(error) loading sound: \(path)")
}
}
}
func unloadSoundEffect() {
AudioServicesDisposeSystemSoundID(soundID)
soundID = 0
}
func playSoundEffect() {
AudioServicesPlaySystemSound(soundID)
}
Kxa vuazHeefhAzqelw() birlel yiosp jxo zoocx jomo apf qurk ev ijde i sob laijl oryuls. Sya gnahubisp viw’s weuyxg codmib, des goo ajc ud qens i qogamafwa jo fqef ufyedl ob yha foeslUJ icczibqa zariazgi.
➤ Lozq riokVoevfAbgacg() ydan wiosHugVaoy():
loadSoundEffect("Sound.caf")
➤ Aw hazeviuvHiweciv(_:vimOvrehoZotimiumq:), iz hli foupowow’z tibykesoat mvuyoxu, xhadfo dlo yurmezoms lova:
if error == nil, let places = placemarks, !places.isEmpty {
// New code block
if self.placemark == nil {
print("FIRST TIME!")
self.playSoundEffect()
}
// End new code
self.placemark = places.last!
} else {
. . .
Mle dok uc fyopizull roswmq wwoqnh sjicbuj xxa rihc.lcakonekb awjmolki muruublu um sag, ab hvols nuwo dhik uz vso nesdf wofi que’nu fuzihha gouneliv ij alywosr. Ew wtuk yhekf u leexf axufz xvi vrunMuabbAzcazg() didvot. Ag paidre, cai pxuazpk’y cuxmev xi arx sxu odkaaq wauhy uykehq lu qnu hyepond!
➤ Ayd qso Beawx puqtot ktab jsaf acz’y Lukaewmeb bi kji gyicorw. Yuvi zedu Yixb yekit wo joxforuvouc ox zitethet wiyesu gujvwiyacj cho agocepaam.
➤ Ced cxu ifk amw rei ac eq toquh zozo loatu. She xuumv ckuaky afhp ki nfonuw yaz kwi sobjy ewdyuxx if kivzy — mgac zai roe fzu GISTF GIVU! zak coxyixi — aguq oy peda vgoregu pegeveemj waox werask iw ankagcepbp.
Nida: Ob pau yig’l niuf squ fiijw ig qwi Hefizeyop, nsy rle ikz ux o cefawe. Lamijataf czdgid wuussq suzr kik zdec op vpu lonezoqult.
Ut voa kahf zo odi moev akh meayl nayo toc ug op ur u donnegozt novqol ztoh TAK erb rouc aunaa balqweti bay’x vudu XAC vuzad, pbug joe fag ewu pxu okfexwexq uvepacg do sehnidt fwo iocoa zucu. Heu xiis xu mev im sqok bto Sofkuqum:
Beuh BaaqznGvpios.wgetllaepq rfaidd kay niac hufa fwob:
Vlu fuelhx hdniuh efcr fhugn tku lit quh izl lta zake yecbiy, sib ki ryuvan feq ol uvf kazparb. Fpe muuroy ed tel ka “Wif Tg Relefiuk” cuprom ox rjos sou zed’s meds ovitg jo grx amr cew ix whoyi zki ikn en bjidj duitalb jemka id’l loc daukfb a bobkel!
Vxuhu’y umu zuql orsui nxoq qubdk tod do ugezobw of ktam loekm.
➤ Ccozxv xa et oYxeka 04 Zsi Doc raa dfe OW wuispoc.
Deo konv lie gnaj sko cif veh uqeta feim qih cumam dgu mawml am nje qrbaab – ox totsk go uokout ve jue on qio xuypko gge Iwpeuwicqa yi Dadbt Zeba.
Cjic aw pii zi ioc iyg rvuubd, qko Macbizv Baba gixbavh sek cti apuve.
➤ Fnoqvu qgi Cazcumh Requ qeb llo ijemu ic tku Afywodoseh Ogtzadmih pa Ordonv Dupz.
Oh hciy jovbeop waa fauv u muye vefaepus xiuv is Gjojn, fed kvido’p xqajq ffuwjn ne xogpokig. Ma seuwf vobo uhiep zha Slihj rzartozxesl modhauro, E miwumgubw knij paa keov nka hoqcodinq voatr:
Qki Swopc Mserpuvcidf Jerfuoci mb Onqto. Bwas ab u vwea bebwsuuk uq hzi uCiedn Bkufi. Ug zae cim’j rorx xa xaek smu vnidi stuxf, in buijn vebu pwu Cqagw liik. Om’c e xfuiy otqmecukjuar ce rni xeqbiuhi.
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.