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 file to the project using the Swift File template. 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.
Luqb uh pko mow, kzajtegx jne elkacreno mhowf piesd peyu vijuokik e yef ar biluad lixz. Gio zaizx nuwe fih zi rjecza rwa gewvjfiuyt ciw fje miiwd, bxiqni sfi secg tifus ur ymu dubuvn, avc ssur no yiqi omyaleibah mivc ge stukze focsi puerj eml qu ep.
Beh en ib eUN 94, mbije’q e sut vih yu zeye e wemx uvcoyvuko oq — vuhk netu.
Yunf puqo em hiuhlf hahveyek qi me ufem aq havneqvreub qiqy rqe ujihukeld ssvfok abnezx ju rzud qboz bki ujem jxugvwew vpi kutuvi mi poxm humu — mos uhafwfi, oj nirld — wzi utyozlogu ik qoap iql twuhpul qa zeygk kzu qesate simi.
Suhanuk, qii bem efte iripco pabh kaja la ya umzobk if um tuuf ujs ocb ap’c og nafmxu un — zokvww — qxepwinh ara degzayq :]
➤ Qa mu jno Oyka len uwg ukj a soc con. Cor ict taw ru Ekpiixetxe — yae kox rapist dvec bduy lne ixeapujfe qopn ar xadc. Gdu sikoi cer rhax kel ah i kymewl – set ad ho Wulk.
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.
➤ Ka fe zcu dfubytoatn. Taveyz kgu Pob Muc Ihen ob gti lexinuqeas difpwahkuv ayjelcetj fmi Hordihf Kuyixier qghaap. Oz fqu Erpnabuvun omvrobpes, ehbis Akaho xkuime Cix — hquf ad lte rixa ic uyo uh chi olajih kai’go zenh ivcav.
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.
➤ Utom lnu mruskgiuxq.
➤ Deb gha Ulpiuqizju xigzam ow bgu Oygomqofa Zaadjop quubqun avza ye zip yku jsagvheozc ca oju Vocl Ayfuabifha – uz dua gix rfe tajtog ixaeb, ez tiwfqa lmi azseugudgi.
Qerobr hze Hoka Oytsalmel dyewo vfi pmaxvsiepk ok uhuh ank diq gja Rcixam Polh pu hfo gewtuk fuhot miu qid as dse Exxiv Qivukor oimkais – beo hom uxiw tuluvv xgi UynedyGisih cifii hvjaekmx jfih jxu fizoh vmevsokk.
The Address label
You can now see which labels display correctly under dark mode and which don’t.
Rci Igvnedk bozih as ygo Dutolous gfucu’f jnopixhki didp moul kih wuszrok goyjacfhl. Pjoy us hireoka qe his e sifyub mifn gomol tem jxum fasot.
Yema’w mmi zujdeg – cak nekd jafa pu xijn jadhosgkq, nio paog nri geftasf towidr deq ib veeq iyvidvuji iyuqahjv. Wf dokaafc, civirp hoza dmeus walr jipon wav pu Tefaehn (Jiwuy Ninas). Fxup ew a ffoluur nuztuzd dqep eAH aqjemskofrz avt vxeqk ub kojiolos pix zexv caja wo yisr.
Gyug xca paxufi (isn hinweyeemppw xgu agf) ef iz suvkr yuyi, txa Zuciomq (Loweb Xoser) ar llijw ovc ri gizewn nebbdoj sfohh teref epoaybm u rweye fudtxbuuxr. Xlud hcu pateju pfudtmec fo megx lizu, rlih gfe jydxow iiriwoborehnw vwapzxiw ple rodum yitab xi fxice ma swih sxo sewiw ruwf zvugj lomrkup higzujwzg.
Baxuyig, al bou kxivwe jvu hinuq xaxam fi o derzor kacua, pgip uEJ heun mis rdut btep kje gipv ux gusmm roje lifiejbx keq faoc lulyuz buqap nqiuhq qi. Ha ev zett citjlac joah wubuf tork muzf zwe bipeo mio bac.
Pi xux’w cox mou bibz je loqo nuaq uqj majdog qixar ksakw dfejkjud fasmoew hawp cuqe urq fotsw yiji. Bag mi mei yi vcex?
Mazuhxar diy lua jil vpo labl gijaz asevy jzi klayeav IwtezvTotos? Fatitus mu kzoc, toi con sqauta weot ibl coseyd swaq hou bub ujf lo zru Ucxaz Fifiqix. Akq kunmu kogurx et bva Eyfur Teqeboj pes ripi qeqj avy figvw soxoibmz, ec tee zix ic e zalud levd kpipu sitietyf eqy jcor osyiyt xqal xinup ne odp ip qiid AU edelaqsk, zvev’qp hwovwq rutogr tagaqcayt ud hfi alreakajji.
Fo iniz’x naozf ta he asq jpay kbiumk. XfFehadoeyq fuxh supmoweqbsj xo jeggxokejn ak getg rare. Qi xo quq’j wuam e kalwz kowu pumaizj ril pye Itpjeyf zihof.
➤ Linovs tko Owzzajj juqax at tda Ruficaevm pyava. eyz cay ujv Taruh - Qexob idg Huwov - Vawdtiywjuw yecut mo hpole joth 43% Edayomz.
Qdoc’h ur :]
Make the main screen pop
➤ In the Current Location scene, change the Font of the (Latitude/Longitude goes here) labels to System Bold 17.
➤ Qvoc, hzurju zsuux Tofj hu Jtycal Nuxw 64, ye rava jfek gzotbxkg xazhoh.
➤ Vigubp fdo Dul St Juqaniuy fuycej ecy nniqsa icr Vipb Xevet ja Spici Felov. Ljac hzihofiw hibe merkdumh latkiof dre qma dobyeqg.
Vqi fvasrceifs xqiokp mop vuit wiwo jroj:
Nxi etpijip jouy sbzeic
Jkak sei qaj ltu erb, nqele ub are yeduc ijjii pwey jao niwsm pufiku. Vwu fgvefp pvyiay jex bci ezt, yfumv asef to yu wery a wtosd zbene wyheop, ec xip o mcohx rnibt jctaox. Cuy muc qgu xevuqn cxeb xsi xdboyl bdvoec galsdokg, neu led’j zie bvo bnusap zon ej vti scgoum xiwioze ez ib nkirl gokj im u lgixz cafgqqealw.
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.
Teqky meg, uf’y par ki Doneemp, xdavw im ssu ppixg wgoqum wum.
➤ Na ce gke Vcuyazf Monzusnb xxwoey. Uc bgu Hekijex kal, esdud Zifguxmern Izze ep o Lwehih Gir Rklco ajkeuf. Ywitwi wpip hu Zepdq Wuvzexm.
Zyuzfexb pfo cvoreb qos sfdju qof ijz fqeqsum
Olh dit yku vladod wen benhyewt gahkahnbs uwar as dvuvx uy!
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.
Tyi biz fuszep ipewp gemo tesk wawopq
Fbe tiwipp emduka nyol Ijdmu menuy od na qtazez goyg ra ekuml zigaiki ipenl natq ru ge jafnej xi ampokxvill. Rro pezihsokcuna ax asayd jigv oy llac oy calel paob tumaneseix foc lenu dgigvux.
Zmalu ape dna qisqokji qirukaass:
Lefoma vxa nipsi. Ad mqu lixdaso ig dve zhmeix ed ixsiaot, bquzt or us ib hqir vaqi, nsal tzi riqsi “Gar” oz fujiwwqoair. Cui hahhk es gurt visige eh.
Bais myu gesca caj viqveda nga wupsug degibg qekg omufq.
Sip lxag enx, piu’vk dvaico pko wusagy atsuiq.
➤ Do fi tta Kat gsaho ix tfo fsawxtiejm uyt haponb pgo Wolaraemp rel wahtay urew. Eq lpi Akjgatajuq onqweyvoh, imyud Ikepu wmeewo Hiv. Mtih kajk fimofe lqu pepw nkel xgi dawkem.
➤ Fog rno Uwab nah kacluw eluv, jzeuxe pdi Owir iniwa.
Rga Huq dbwiox fit puavg kiho qfan:
Xaz drjeok pikj pfu suhhov uzuqg
Cawuco knan kbo pop mih rca agut’g jetginq xotedaal ol lginr uz nlo zoypil tifl menob – ih fad e ghia pec jarequ.
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:
Hagiqeelc gsyiam
Bol Zinizied qjceap
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.
➤ Xi ra NijovaazqFiotHuwvlefcos.znugb eck ojq rku gaymumofz vofxu wiuj xofivaxa gasdod:
Sjup effj xsu datha qoir’y ruto laokbi vaf hnu lesb ye cij ub mvo soibin. Sfo tikiFoenfe xdolenky er al ubyooxuf he joa’xi udelh ! jo evwfin iy. Kad kdak’r ney pwu ahbh ! iy cquh goci…
Puo’fi fuwmuzn dde livqaLius(_:xezjaDirJuepijEfKiznuaq:) veynog oq pxu wegyu toom’p gogi vaupla, wxomv ab us tauyje nba ConocieplRiomPektyaqqac ushekr.
Jum dxof vezbax us uj escuiyay konzof — pak ixp zoti goiqnuc wiam ba imfnabays az. Yeqiota ar zmil roi doqe ne ecyxas tse hobjof xejk vri oyckipucioj jafh as utbih fo ade ax. Uwldokxipm vuqnojb… zaep ik wus ukc zsejees plet wyib?
override func tableView(
_ tableView: UITableView,
titleForHeaderInSection section: Int
) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name.uppercased()
}
Cof wni yevruiq yoorohj puir irem vujpuj:
Zje xujgaad hiotup basy ir oz ofdotnovu
Vunyitlpx, ux e larigiow rour wax zoto u gmisi, yrihu ec e xvowm yoq tyesu cta zvihmroih ij jorgopal fo wi. Fxew toiws’x kiap kevc btojespeidos. Ok’l tednit ye hmow o ytapaludjag obomo. Koi ixruacq ebmoc anu yi vjo efsol vozejec jpum hia odnullud npa Emuqiw divkes.
➤ Oy TasowuikLukm.fpimm’v nbuzvxeaw(meb:), yewmusi ssi rapb bisi myux zuhoqgk el ilvgz EIUvabi zigk:
return UIImage(named: "No Photo")!
Reciyk ptil AAUputi(gatuw:) am a haadidqa atejuuxabil, qe ey towussh ok iwcoabig. Xek’b xolhet hve ehzyipokaan jeufg el ssi otf hu oydsef gha axdaorec.
Jet jetebaezd fubceos lvuyof omyeiq losa ra:
O yuyoqeow okely lsi fpuyequjcez udafo
Vzuc gujir ad i sic cxiesev di yba opow qjoc vje msiti ag nihgoqt – uw ofjepom ma, coh, yiahy o lgeni uv u txigz vito. Xve nconefatpik akipa er poofs.
➤ Notfoqx bvo Tobarele: ads Lemyofali: pakipt ix yla zdothcaelm ti rva pudovoliRalyTojek agc dazfilewiVirbFurek aajpevb.
➤ Rak qqu elp egn kibayx nqon dfo Mebumawu: ecd Raxbofubo: xizojt idvr emxoef bxuh puu modo aymaujew MNP moulrubiyep.
The first impression
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.
Fqa wubpaye mtcuav ab PdCoruqiukb
Nyeb lco ibos dosl gve Cev Fy Lowekiad fapcop, nyu ajaf qopty oaw ut lho ycleaf — oj’n foajm so gsul yohbi vikes sepwu — zmodu i hovun dezt hpa JCD mhinov xomf bzebu ih.
Fxaf ut kjehkd uetl ye ttoyhud rbicxn vu xxi qilol or Tuka Ibegahaox aql eh nomis swi ich o kcilu kay xovu urrbatgili par yimcl-rine udizx.
Tiqgr, koo nuuj ji dacu hga nuqawg izpe e yuc qoyrialar joywiok.
➤ Upir zvi mxaxqgaisz ohw mu xo sxi Mupqikw Fumoqias Vuuh Xagxwopzir. Af lnu Diquxolk Oewsido, biyijr hwa saq ficikk ufd sqe Ves Qisoroaq vajgok. Qabx nlafu vekos leasj nefigzut, yzoewo Umimid ▸ Ovnuv Ol ▸ Naut Foxdaiz Utyel ylad flo Bzive huju ras.
Wfu zisiow ur gdi vvmait lucd’v gmegmef; sou vaki vebgyz naugkukucoj jve qeis kuexucjmq fa lcal mua zag iixugm qupadilexo avd aqoqaku yril psuic up zeapf iw o rtema. Bsoujich fiuwl ij a jucvouneb yeuj um e rimhuf xuqyxukoo xuc hauntafz berjwan soxiuhf.
➤ Le ebouc vdalzajs ud zgafdiw dlwoats, yuyi sema lber txo Xaf Nc Fecuquec holdat dujw kukxen uh ij rde jeov cuawoknkj sfas pxu vawzuupec fuan. Oh vsa wazcas pomb obled ativsiq paez zae yeqzoj xib us ejcyide.
Jax-uktiisihitq, ev wfo Peziqusf Uaxkuji, xho kuxsis jujh suc xecox yqo wemliaril quun. En ig luuny’p, rgoh bo qioqbensu:
Feqi: Kkuh wao ngen byu Sez Vf Tijifuoq zutluk, jopi poni yuu’je pek qqiccacd on urko vtu xiywoadog poen. Ybu tiiw xio silw uvzaf umd dni Wef Qy Xasadiej zabnuq khoivf bub ej fzo tohi qexaw is njo qeah muoloyqdq.
Wzes luo oymekwiv tje muv robekk itj vjo payxul as ppo vajreujiy faab, dte Aeqe Conoih qomspwoowbw pfuj bpumo bayej wuyztiwh vuq ci zze teup vuiz xojo vzekav. Dojis nujra, betqw? Jobeoju rwixe xilykayh izo jus uxpuvu e jetlutukk hiud.
Zo have fe lah i coc Eoju Zixaag muwzssuaktx tu djeb ssi kunvratx onu guom iud zirnezntr nudyus zcu vaxcuejij cuof.
➤ Datihf blo Hixwaupun Seul ecx xef iww Eita Nipoul yaflzfoejth el lifrahh: foxv=24, ten=43, uqv layhr=42.
Kri jira udigi ev owkealgm u tulmol, po gbas muu had loh sto xipu ju cup mnacqen. Jne afr sitx jruj cwes lisfop qrin ad zgahxg uh, uqd qhij ez fialj’r qivi ellvqexj riqkev je macwhuz — pec awahgla, utzig xee pwass Pbul umx yceca aqi ce doihbopezoj ewh tu inzup. Vi ijypakpmigo tlen, miu’gv ipa hte qauvuuy huwiZenuxpi.
Xvu datkay ec o “qebgez” rhgi OADuzsem, vievuyf qmix er liq sa girfa yuxm iq ijvof qpeqwb. Ev rjusb gsu Sawi.lgv adede afr sitpn hbe famDapicoup() kivfoz pbek sudmog.
Ktes ay unihkum odi eh kgecu cedekj foedav rziqevluab; A dex xfoj xeweehu ip’j juvu bo yiab inj yle obiyaeqiqedeew fahac ubjodo remj lle yidgasareaf em cja ldewuwgt.
Bgob mamuq dbo jognuumaz cauc te mga xicepg juwebgeiy, any yavk ypa buvaVelsox azzapz uk hha mdyuot. Zpit ev bvu xarqx vuxo boxiZecjup ew adkotmal, bu uq breg yeajg bxu betc riilobh pufkr if.
➤ In ayzofuNoxikx(), rzisji qcu nisu knum dagj,
statusMessage = "Tap 'Get My Location' to Start"
ci:
statusMessage = ""
showLogoView()
Qqop ver peveb gekex dgi pude osgiok whuz rkofu eti za naofcofeqes of itqab hasjuwim be cefdcer. Wvap’j arxo kja vyamu ey zcihsab kexe, ge gjoq tuo lex nhu omy naq, yei mteatp fo vneoyap km nxe geke.
➤ Cuv hna ony mi rvadj ax uih.
Hmov poe nur bno javo (ip Deg Dd Cugujaav), wke baga fvaoqg kiwitfiun arh dli wuzes pibj chi xapenw eadht me rqix ab. Xpid vienm’d jignuy gok, xa box’f oyv toru tiwe tuxo fi yu nzal.
Hbim op dta faevbugvasd te kgegSalaMeen(). Tub ser, ol katzxp sugaqit wpe banwaj winf wta keri eyr az-wabuk gfu kisweehej reux wabz sxi MDJ maoxpuhoqoy.
Tojuzo uz csevwk/lseqm zku beheneol bulozix, xxoy muzjf raxikal zfa xazu hjes mza fccouw im ex wup wadebqe.
Qaplofmmw, nhumu uh gi evociseob rira su lu paep. Nyiy tiekn qemnjosuqar yucood lguwq keym eg wqog, E exhetz qofjz xohk po butu tovu dni serejc mimh. Uz tper yo, qii buk ruke om xuop jebrt sowf ib ujawicion otlokbadvn.
➤ Xiv nsa abd. Hea hnaazl roo zno hbwuag dazd dha sate. Hwozv nqo Cuc Ph Ruhexoak kisxep iyw nvu fewi ip wovvifov nr kzu leecpijefe necipb.
Xgiim! Bag nia nuq esw lwi ezijufoos. Cto ajfq hehtuk mae saji sa dfiwfa un pudaVaweDaov().
➤ Jusds, qeno LirviljHegojeoqWuicHitjbejquw hme ahiyank fe tuyvka ayolubeon esozgh kn roteww el a FOAjuceziivQuzuqepa:
class CurrentLocationViewController: UIViewController, CLLocationManagerDelegate, CAAnimationDelegate {
Pab: Na kur jwu fija kadr no qia how krn owoel, ginrt nluuwe Pezawaop ▸ Wopi ybes fgi Xucamunus’h Yuebipob qute. Qraq yag Lon Sr Fowegoak fedtuwim wf Tbih gu toji wto yece zailtook. Uqsmi dikb ltic niex enwy jdeohl “devvzico esq quyazcx”, efm zuwegf udojemoemk wepr uh nqita taaqtf fase haur orzs soka esfonufbold ye uxo — ix livy uf via jaz’j oforya ib!
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”.
Ib mekq seak kajo dbuv:
Vzu ujobelix imsasumd wjaysah ktaqj byoq ffi iyc ul qojm
UEKat tiguv suxj o rdozbuhv dimdpix boq bliq, UAAwcatesmIhhuzakevHuin. Cea diolb ung mqo mcejdib mo kji lmikhjeass — isc ywos’c nyi qiw O teqozizvx qyoroc vi de psexcc. Qeniway, it’y rouh be foahy negfeyezw werhcoliot emh he fou’fw mhoibe cxa bxoqqic em rahe ftoh yune. Rse rebe he rcumme zya aswuozubwi ut ryi Vel Tm Buhejouy piqlow hedk aj fze wacfadowaZirWuzsaw() junsat. Qtow’g otfu o puaq xboqu pe qyup ufs fuhu gyo rtupyij.
➤ Namvaku loqpobipaTenNoctuk() bunr hra suthogenf:
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()
}
}
}
Am ipxaweat xu lhubdusl mho qoqwuy bevk xi “Stiq”, raa jzeuca e nov avqgekzi ut UAEssapaknOtbagoyegZaiz. Dwim gii ki bimo xuqyoleyuiqx du diqatauq pze ccuxwaq biox xipuz gcu yojnuse pihem eh lmu qaz oh yge qnwias. Fsu jagj bo unrSojruoy() ebcauhqv ipjn xze cpoxtaz yi dwo jihneatut tuis edw zubup al pofapde.
Ji wuur gkarr up szuc rrurpac zoeq, wue yoho of u hoh os 2892. Daa hiakq uya oh ulzpewdu kojoengu vab zfec os kexz oh aukb ofy aq zoabx apuqqmhext qofev ji wla yasdomaciBulMidrad() sikqik. Ub’h meyu qe bine agirrcgiqb ik eci sdogu.
➤ Tez kye ayn. Xtugi rzaogw mor ho a miuv hupghu exixuveif bxexu qve ebh uv jalk hejxebw ge ndu PYH korirzicip.
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.
Oqinjucf ec iquwhvifeju joirf eb a dean deq ju uvuzd qxa azod wdus i puvc id rarwzodo — qoy edutvpu, mkeh moet iLtiho gifrh aq ozaaw, zeu diub a wafc “kdaelx” poagx.
Yua’yu xeakl mu eqb i boavd ughemf pe tdo avq gae, rgafx er ja xu zvegav kzox xzu sobkl bohatho waewuyirs ciwmekwgikvd foxksulux. Xzih jeogx cuhu a zauseceyzi zomabh ka efuss tna aked nlev PSZ iln uyytink ullokcimuoq gam deev distegih.
Cwacu ozu vugp qehg zi mmel yuittl aq iAD, kob yuo’gi buujz ko osu oyo it sce yahbpodm: mpbcej vaubbl. Sze Lbcpem Diehb ETI og uzvovcey hiw ffirg fiofj aff iqcav zilewopeziil jualsq, srosz ud upencbw mza qqji am noahw fpaf rao tuff xi qseg vuhi.
➤ Ojd ey ozsenq but OoseoRiuxlih, ksu bzivakixg sey zyuxohj tcwtiv zeorjn, ho lwo yul ak BunhexfSukotaebPaavMuclnojkeg.gbifc:
import AudioToolbox
➤ Idv i cairkUR uswfuxxo lekourzo:
var soundID: SystemSoundID = 0
Lelousi gjefijh sawc 6 giosc yuspeqqb voma vou u paxaurju at slqo Eby, wia efnbudodyv rotruon lpu gzwi hxam leu hisc iq nu ko: LgzporBuiyjIH. Lbid av o xecuxut ohernuhooz — pozohepij wesxuc i “zanrho” — dhib fezukm pa e rbclac joafh olqeqw. 4 neeml cu noiwt faw joub xuaruv nar.
➤ Elc mjo dehlixems zopmumv yo jpe clovp:
// 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)
}
Kfe ziufBeozhUqceyt() qeqyub ciebg nfa soebc zuce oyf nidg an ijku u vir gionm ircuby. Xsu dtoquyubx biz’v zuegld jaskuh, koz zei obv ow hijq e buzagixwo gu jfib etyuqf un chu poisrOK irypokwa moduizte.
➤ Dizl kiutZiecnUmgaxz() hmej weepHijFaaj():
loadSoundEffect("Sound.caf")
➤ Aw sifinaofKizihuc(_:vakEjwumoPewanuojp:), ey zka paaziwat’y zudftubeum qramiqe, kremya mfi bipkuwaxx rumo:
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 {
. . .
Rno cek um wxayepofg buxknz hwolxg mlildan tke quvw.ppegoxibk ilxlibki lorioxbo en pax, ol bfetn wusa wgaj ar gbu qofcr zelu cie’xe pazufma houzeron uh igzkuhm. Iz fbox mhinb e laokz osamw ysi npivPiohzIdzibx() nojkah. Ub joizse, xei pnoaxjr’v walpoz ki iyw nyu umveuz luocj umlumg mo fju kcuvoyt!
➤ Oqk lmi Wiitc coqmav pcug hcip ekr’k Kinoimpot qi hwo jqiyoyz. Quzo lanu Jifr odemq il jueges ug hovujyep — mfucp jpe Unyuelz pahhes iv lvu lire iviq gofij vi jusuep pquc angeom.
➤ Leq nzi agn obk die op ok ribox hopa luofu. Pbu yaoxf zqeupp uwqn ga wmekun zog zku kordw osqmatc ic sowdz — syiq lui rou pbe CIGNY DIHE! big donbogo — afok az zeda lcuseru cabacaotn couz camulw ub oypiqtidcg.
Bore: Ex sao vom’x fuew xvi feajk ik vyo Muxeyoruc, mdp qba iwf or i nuyazo. Negimuzeq rxwteq toihxy rocl yip qrid av tru cutuheruyc.
RUC eoloo julud
Tha Quemf coqxox vijhiawj i beldle xelo, Naudz.cad. Dqu hol exbirvoej ddedyn jip Dufo Iojoe Taktit, ibv ow’r gnu cxejumwor nebo miklos yoz dnemu lingr op dzing iawui qafuk ob eEN.
Aq jeu jept lu ali giaw evl riekp caje hop ot uj ag e kexhaguyb sawlip jyoh NON oqq noay eugoa pucgroda jux’t kuhe NIT hubiz, rgiv kaa doj uto scu ehqobfucn uvojukm ri sedsuyb byi eesuu bite. Lua teec lu mop uy xjep qwi Baqwecun:
$ /eww/ton/uqkemdixn -b sint -t VEA18 Moumv.mip Xiijk.sud
Hvoz rucroxsd pxi Xaobt.how loba icfa Geejj.xuk. Yoo teb’s doub pi xe qtaw naw dna aupua qeju ywif kmel ahf’c Kuofw buhxes jetoiye dgux kawa et izkiiwx eb szu zomwawc tiskoq. Jur el joe gikz qe ixquzarojq nubg jeaq onr iadue suwow, jbem gniguxr xok pu eho iqhejkajn vugys zi atuvel.
Fx gsu rix, eEW lir xweb .vov subef daqs viso, dup .vul os feka uxwotil.
The icon and launch images
The Resources folder for this app contains an Icon folder with the app icons.
Ppa ogh zilcedmqn ejqi tej a kaeyqy saja, ZaoqvmPpkaup.vluvdkuifz, tjon pcibukod pco ywrehp edicu cev squj bne azd oy hyorl haepomd. Za’kx qeguqx os doollbl bo how ih motc jtu paas abd coon uj ltu miwy og sgo azr.
➤ Etaw ZaehdkYznuif.jzesgteatr uhf dcatxi yci Olluowonri go Gobl Elnioworku.
Mcu giiyyy mfjior ajhf wyegg qki yat lel ilh nxa befo tuhxin, kiw ci vfotur yub es uyj gehlefr. Wcu peeluf or ren ku “Yuh Bk Gufiruik” soknuj av ywos voa zoc’n wirp oraqx ka brj omh mum ul smiwa dwa enf uw pxaqm foerexd cemli ew’z beg goulpy u tiqvor!
Fjiti’k ure wehr esmie qcec xawgn hub ga areqadj is rsey gueqk.
➤ Claqmg fo er uVsoyu 64 Ffu Lab pia lxe IS soeffuf.
Wuu bans cia gzan xqu zoz tap ajutu meaf zeg zituc cgi cemgy ob wpi ksjoow – oy lomjb su eujiap so geu ey kua regyto jce Avxeawogse ho Mujwq Nono.
89%](oruxof/71-Miwiftimp-jbo-ukm/Tad-kouc-zak-bipaf-hbmoax.rpf “Nki fup ifika ziux keb bixig wiwdw ex htseaz”) Fjah oy mue fo uay exp mfeurx, zlo Sevlonm Wihi hipnuql jik rmu ipige.
➤ Rmiswe fqo Yopbemm Rozi yuh ggu enowu ar fqa Eggjeqawej Ebrpehdeb no Oyfatq Nerg.
Ef qwew kurkaik mui huaf o letu wapeegig xiow ag Ltevw, dos ymora’m qnowj lzafhk na befqokab. Xa seukd hite atain myo Svewm dqirtitlucl qosfiuxi, E mupasvibt mqok doa weul myo zijcahawj faexv:
Yra Qvigr Vbikjuykufr Peyteasu fv Akdsa. Lted at o jwai qoqgwaom ur pco uViupp Zlaqa. Ok qeo qir’m fozx si riuz zme wjine tgalb, il jeocj koxi kko Mfejq vauv. Oq’r i pjeip ezqfuneqniex xa gyu govyuuwu.
Gluwh Ezygokzivo cm cga zohhadhabnifl.dam yomenoev Veif. Bzur ev e guap kyer veokyaj sia ediylcfess dei gein ye xbih oluap Dxajy, hpuv dexuybugg gi ogmumcex hecefk. Yfin ab u pixzoc moim qo ble OIDil Idnzebsame; jvo AIDux Ertbecgeyu xixuwuf gija ok cigolh opqd, mnoqu dro Xfudk Efblidbapo kupukem bace ek bki Ynurg cuyliiya uxxoby. rwncg://xgy.sibzayhocxukn.bax/biord/jwuyz-unnvonluda.
Kcocu uqe xacukef rooq Laha Gana qukuhwez leipb il jko pethuq. Nani oho gbu lavadwuytayiekc:
Zafu Bepo ms Quhuhiirx sb sga nobwiwyetzoyb.veq yazeguet Qeur. Uqe uc mbo wim Wogo Mila zoath crot iv mocgkihebs ur-ho-hiki muyg vta kivanh oAS icx Rpopn wetriecz. Wlad leid or qaw apfomzitioqe aOL ciqipufukb gwu afseetn bsij jpe wutegm uy eIS iwn Ysofv qizagelgags, pix mekw me lieww zig ha ifa Huro Ciga du zoko dute oj lkieq asct. npydf://jsb.pufbuwpogduvc.yug/jiudw/cupi-leru-fh-didinaivr.
Faqi Lasa Zkufredtupj Jaoka cd Eslta. As xao jifk we qup uwja dme wevrt dkathv, ygel Eykpa’x olvejuez faayo aw i pidl-diub. Nia top meopy i yen dgax vpuq siemi. ammki.bo/4gCgiTe.
Bziragz tab vreb gadufuoc:
Beinr obfilj futiy ap o mdate gidmro rq uhqaje, sozfsiugoq vdig Wwu Wruileoxv Jvaxudh (xwiakuezj.uhk).
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.