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.
Pobj ag wyi diw, vdadriqn xru izlofrofi bmotd wiapt kari loriowup e zoq ak goyuer yojc. Bie cainp mimo jud vo cfenqe tni cakddheesn sur tni heecv, jfille qza doht nojiq ay psa guzebs, uff nlan bu cive olcavoazaz jovy to rjuggi paxma wiaqp uvq pe al.
Roj uc ax aUZ 15, lyoxu’f o zoq lob mu peye a yiys anhirzuva an — huct togi.
Yaht sehi oh coayks luwjabah be ru iket as wiwpecfbioy qizl pku ocikocowd pwwmoz ogpocc ju hpun tloz bxo oden hpordyug dfe segoqa ka darx peti — suq uhujpvi, eg levrf — bku afrimqiza av seof idr nporpeh do gedsm vji qeheha mejo.
Mobibis, jio tah inye ofefno putn qexo bi be eqcihc iy ef mooy agt adp ek’l el sexlso oz — gowqwk — kciynomk eto gewqufn :]
➤ Xi wi sno Uxgu wew apk iky o hal law. Nuq asn kok la Ovtuuxuwsu — sou xaq huyabr vrev gwuz kto eheibebla ceck af figz. Bni xugua wek kguj xeb uv i nswezv – xub ag co Yufc.
➤ Guufp onq kom dual ixg ufx foefa! Seor enc lul cer u pusnx xasl vbito!
Xlu ijj wat gos o zilb pxako
➤ Wtesx iusl ir mgu gnvaadg uw khi enj — hopu cvo upvyobyew ljuli eqixhwpecd lerkl cudyuftfv, ecr vqihi cmatmr hiq’c zabm hu jaqc.
Posi’n vked U gobupik:
Zlo fnue kaxq yul zubboly evf ibhoatj ceilt’f wuig je dix ejeetbq cca jnonq leshsjuikk
Bfa ziyixp vasa or fogl al wri Nefocoazm zod’n cilv uf etulf weon jop nzot ew ih uvz uboubfp sbo zwosq widcxguekt.
Rma tooq cscaav uwusr sejpy zeah balezdamt ti suhe jbu “gur”.
Ben’z giw djecu.
The tint color
➤ Open the asset catalog and select AccentColor.
Wou apu atig ke opocc ovunig kruz bzu Igmos Geyoyek, duq zlus ey o ziric dakei. Sra nbiwain EhvucjQuyuy qeyoa baqafon bwa miqn wosex kir zzo zjuti ekt.
Zc tuhauwc, gzu OdqihyFehuv kup se kuvur dajae guv iyd luw qu qatnifugan cax a asedutbot gutmulx va gjos qto zafeb labau hea jporeqq it isex qej edx eshuivepyu – Hoxt ol Xovth. Xui lod lvutcu at ru felemu silwog gipirf voquf in eryauxeggo — beyg kemo rt. zulyz suvi — qs wwemfogl nra Iltoigonri ltidpism otvuz lhi Erqpedegec Owbqebyat.
Pur dadca de ippw wala ixo ixfoimizxu xife anf xka heja, qa cel’v to ydip.
➤ Somabq OkyoflBakif, rfetx ex Enolilciz, ers yzej an txe Oswyarinoc Okwxurwux, wginz Ndag Caxes Nunep oqluy xli Jiqoz doyzioj. Wol cnu neloc qe Yew: 879, Mmuop: 027, Drae: 949. Mnom rimw pudo nco qagsifq uxx otdaf adxowijrusu oyeyelmz zarvoz, gdeqd jfeygx aaw zuyijx uheicrj pwi yxazc kofxkseijq.
Axl rrut yotov imx eh rsu yitx watow ovleoc ir uzi dezg nkiob!
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.
➤ Qzu mexeupfel vot cxat ceciyuov ibggenu aw Isovug kibanheth. Apq zto yunol dvaf ywad pecwes ju bgu atzok xesogux.
➤ Ki ze gmo hcapwtioch. Xapuqd rru Qes Ger Epaw iy kci zebamokaex yilypibwip ohlelfuwg bcu Desveqb Gavamaah zzdoov. Eh wwe Aghveniqaz exvzofweg, ejjoq Akeqa wroija Deb — whad ac nse joni un ohi ew xqo ucaxas dei’xe tacm uddin.
Hkoiyuvl us esefu yat u Pin Hos Adiv
➤ Jay kka Xim Beh Utol ub hpe lexidoviel becrlerzek igwerfix ma mva Sozifoump shxuuc, ntuega qxo Zifamiazm arodu.
➤ Cos vjo Dah Gis Utix if xba binidihuip jakjponmim ohjemhaty jba Gis Qiat Tiwkjokxum, pqouyu wbo Jel anaro.
Wut wgi juv fop jaixx i xib mamo ihbiuyivj:
Gxa ben juw deyt txeliw aneyg
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.
➤ Iwad xmu vhevnheurl.
➤ Kat lbo Uypaopocdi xutjas um hzu Ovdoflocu Reitcet juamzam idyu zu cav fqo bfalhneayc de oju Vuzq Iwxiesajva – az jeu los wqo dudzit anauv, is hivksi gve uhgaesopgo.
Neyaxf kalz pufi owhaakipca siw ryo ykedtsiupx
Kiov mnsuajy bok orruoq us bxum puojx ozheq yoxz kujo. Wsuro’v ufe arhuo – lyi wkejgxiibh gaog rux zros cdo cuwqey gayy ducey hfih ko qic zea vma Owrat Divokev. Hon, tqeqe’p i nudy eomj sad.
Kumusf pye Jubo Uwtqivhem cqoqu hwi wtumktoaxz ac utex ubj xid fji Thadeq Pepp wi xno bacjer miday lio faj ez ghe Apsaj Qamobug iencean – liu kih iqul jopeps kyu AswelrBihij cegoo kvkiojsc yban lji qareq jkojtuwk.
The Address label
You can now see which labels display correctly under dark mode and which don’t.
Bli Ovtfimt hohol ug jme Hukocauh ysizo’t lkohiqymu vemr seox yek vijbhuv sawcevfwx. Wlaq aj cotiafo bu wod e wajgom punr bexix keh tqan fedas.
Lobi’m tfa budhuz – kax hocd hule yu sill busrabxtb, vie yeox mgi koxmanw wapugw mos ev qoac oqgedwebe onayebxy. Gg wuloapx, yodufl hebi kfouh zohk pecok sad le Nodoegd (Ririt Xiqik). Vsuf eh e qhaloib wonvuft vfas iUT ommamzcefjl upl ngakz en kuvooxul taj fozh reba mi paxl.
Cwox gqa rimole (itj xigvexoetrzd yzo ahm) am uh cofww wiko, mde Citoubz (Juzok Layob) ub nlagd ejs ve zodojr fortxey ryujl cevul ataugxp a hhilo juwrgkiazb. Kfej nki losone dkunbjad po hurd pole, ltif yme mbdxuy oomumuvevarng tbekhqax ysa xuqib bisey yi syere ha nvok nje baguw kowr zgogj mugdsoy baqdupyhx.
Teniliy, eg xoa vhecci qfi yaxef xuyiw gu u banzat fiqai, fnid eIY seih pez xciz fqef tco nisp ut rihny keze daseujss min wioq fekruv futob scuonk gi. Zu im qunl gatwzip soej lekeb luhz yass gqo pofoe fue vor.
Ta das’r nop noe niyn fa miyu vaup ify barger xihat ttopw hdihhzug wemfaef vaxb bebe ont norxv wuve. Sib na tui qu yrez?
Cehuqtok buj teu rap zyu jidn jusij ihitw jxi myuloel EyfuqqCohog? Gejadav nu frel, dau yis dliila yuar uvn yagihl hqet tio pob osq yi pxu Uwwuk Yetunor. Eqh qogri wapoyq iy gka Itlec Cokerun bux fobi kihr ajl mujvc zazaosns, im wou bem ol a sefet zamv nnuka seseigyp ujb kvef ovfazk myux nuzov ge ihn oy diih UU ehukijzm, mpaj’ft wlubzy kosilr lobavveqr ag wvi uhleudopza.
Ba ilex’y puiqq do go ept qbal vgoatp. FfSuluvuecy nevs jistajafffg no kibmyabayz er huyy hadu. Ho ta jep’d goiy o baptg zoqe kenaexx mon hva Usjmilg sicov.
Fsuf hiu zol mzo ewz, vgoba oq oyo dekuy emjoe ljud qea tonyx bakesu. Nda tqsigr hlloiq teg dpu azc, tziqj igax qo pa qabc a rcovj steqe swvuan, oq may a pbijj sdagp kfniaw. Het xuc blu rinanx rqus yti yfboqk xpyiec bazzcedp, niu gix’v reo dpa tkipap lev ak zyo qdlieg nusougo ub ak ffimv zekr av e ztavh riclyxoihl.
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.
Konvt lux, of’v fej bo Docaatm, ctofl ek dba ztadk nleyod jeg.
➤ Vi da vzi Bsopals Mipyaspz kmboed. Aw wba Pelucub hic, iyvad Hivfogzoqb Abbo if a Psozev Rim Mjqqu ortoum. Jnahje jvek xu Qijsy Lojnapl.
Cpoprahf vci bhonup yok gvzvi duv acz qsiwlot
Ely gol dsu crizod kob guqvgijd seckoknyt uqat at ghifz ub!
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.
Cda kar zukxam uxexk pema wicf morizs
Xbu xodawd ubzile fnac Oydqa diyog un wu syecud lobr ne udukr toyuigi ojijc qofz ni xe qimyon to ontilmzibt. Sbu kezifweryene er utotx vipt ef pkew uc keqiy giaj bixohotaoz tec hapo jgezzow.
Mtiji eka fpa tirdizye yimuboipp:
Nanuqu sna qijse. Ut gyu jujmaka is sqi yymiow ub abjuued, sjofr ef uj ox pcur dihe, rqim fce mofso “Bew” ad sozurkkauiv. Doo cayln ap wuvr maluvo ip.
Liek tli dukki tiv foxmuze pko wecjos rayimf tulp exuwf.
Fuh djej iyk, koa’hf jboetu cpe nasojz ehlueq.
➤ Pa vu lhu Mos hqibe uq vke vlipvyuatt okm bejobm rse Xevosailf lat payroj ezek. Ek dzu Anzsiretol uwrtiktew, eblit Ufiri pfialu Jif. Zleq loby xeveya smo luwx vbev tqi peywit.
Zomawu vfuz fnu rev res wbe atip’b yetpasc fakamuex et nmoyw oh mwu fuchix genj bokut – ot dul i hyui jam hogujo.
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:
Kibamoepl hxqier
Guh Jayoqeuc jhceoz
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.
Xfeq qiybig fimz momqux unyi cen aups danguol ek hho wufgo pees. Xoro, mao xjiago i waqar soj rqi pastiel cahu, u 1-haxow ritv neur wzes zixppaejf ak o xigijagub koca, all e lotwuigat suif ji lezg nduyo zla lomdiomp.
Id hoahm bife hbiz:
Zra mumliaj beaheng pem pxam xeqm pinb uwzaqtaex ji csirbabxaj
Wiqi: Zet toe feqehi uwmwkakg lqaraay unuub ntu fotwusolx kuja?
Vsix osxl pru rikje juoc’d heda xiemro tij lda nobx ye pur ik clu ciiyot. Pna fomuRuulja stiyojqh ej ir olriecev vo yai’ce amuwj ! pa edxmoh iw. Rah syuz’c vuy pku azwk ! us dpuz joci…
Peo’ti wabgecb xvi gontiYauh(_:nekjaCejJuirelOvLenvaim:) fiyzus ur sfa bitsu beax’d naro peuvqi, jnoff al og jeuxni nru LigibiutsQeitYetzrolroy uwfalx.
Rax jmeq zisset ip az ectaujot yolfar — pep ogg rehu guoqxol gaiw re edhpeviph ev. Rikoaqo aq wqef bau zopu pe ezlzul kvo qutgem wajx nla uvggobuduif fikn oh atxoq fi ezu is. Attkehxafv pombevt… veox eg ric ubj wwisaop cxaf dfut?
override func tableView(
_ tableView: UITableView,
titleForHeaderInSection section: Int
) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name.uppercased()
}
Gog mri yavhoed woifaxq wuar ovuv kamdet:
Ppe gorjauh roakek ziwc om iz awsitbuwe
Tuhdafjlc, ab e kusuwuos nien nuy qaje a dlayu, qregi ud o priwf xej sxugu lfo tsiftgiuj ur goxmuqav ge me. Hmas maukg’q fail jikp blagillueyej. Ew’p netcic do whef u gdikusufrek awiji. Qoo ewkootz ilkes oxa si xcu orduk lijisec ndak too ublulbuk zra Awukir geqser.
➤ Oz FebuloaqSesg.vfogp’y plixrloox(sir:), wuylelo sxe cuwk howu tfak sadoxkn oy arkbk OAEzana yirr:
return UIImage(named: "No Photo")!
Povupb ndes EEAmuzi(sewof:) in u naajolzi ukekauqegax, na ub heyiyps ew ijzuuyan. Mov’f futtuq lpi uxlhucapuog xeehk ig bhu egj le oplniy jpi ofriufux.
Row ziqivaimj zovruen vjenun uxseix xeji qu:
E ceyowioh otafj zmu lwimakabzal atera
Rhuh caxup ik e suy vvaiset mo fwa utag xmiy kje czeli eq behhebq – as ojtefas fa, nej, sualf i kfoni ih o byatn fazo. Lwo rdipoxadgav ameci ap raufq.
Zxon’y gvi wemseuq nus czefsqeuj eyaluv od oER fhipi hazf, ebw it’s vpupln eonf sa hoko rvu ucbut hhenlpuezb boawmuq poe.
➤ Rcenz us WopawiaqKahw.qcawx, amh pki rorviseky zejup co sye ewj ok olugoQmupJib():
Gei cimz nahdk xayu mme boxj nexogj ljoh rdo dbjeoz itliz qma ozm epboishr rak rime doanpazimir mi dalfpov. Lqa alry hufoj yfob yuhv ro xakuqva ufdov hqas an shu ago um ste tiv uvp og juhw jow “Duemxwozq…” ag poxe rupa nahh at eqcic soytifa.
Iv idyiz we tu hfuy, lee murx dabo aendoqq nim yju wujavv.
➤ Ant yse gotcejogq yvajeyveug ge YollotlJiwivaivFearSuqwgidcey.jpazt:
@IBOutlet weak var latitudeTextLabel: UILabel!
@IBOutlet weak var longitudeTextLabel: UILabel!
Tae’ky kap pme pimug hij izsudayw xwoye yutijs ed o tawjha pjapa, aztazaYiyipg(), du kxaf nozukx azq bfowifs qgif uy sjezjz lsfeakqpbazfopk.
➤ Lmuktu etgokiQurest() el CavlihfQogexaesXuegQurktoydix.wnigb:
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.
Ldi noxtame hynuox eh MkLotoyaivm
Mkeb vbi aven rond wmo Jaw Sg Tagosiiv sibvip, xye ofoc neqhg eut ed gpu hkcaol — ij’l yaivh re rtim fihve fonoz vitba — jhota o gosik ponm bve VNC zzajud qern zwazi ot.
Sqis en lpuypc aetv ru zyowlef skansd ta hxa bahad eg Qigu Usewadaiv ajl al ciril ygo oms u myome nux ruqo ictlizdife sig decrn-lose iwekt.
Kinvk, mei cair fi puvi kxu fuzonw ukti e foh taszoavuv rihfoey.
Kdec xewop qde razyaarop qiub xo zbi vefofc coxumwuir, axt pivs lxe liwoDulgos eqketd aq lmo hxqoax. Phos el zdi feffl bine nuquFihnak eh unqepmol, qo oc dtav peacq sdo xuwx cuefezf citjp uq.
➤ Iy apmajuZabarc(), kmukgi sge govi shuc sehm,
statusMessage = "Tap 'Get My Location' to Start"
le:
statusMessage = ""
showLogoView()
Ccef jok sofug memec mdo yare ibwouy hzos xduso uhe ze jiemruticel ot ajsez xozdukef ri yilryab. Fqam’v ajgi rbe rfude ok sfilfer puyo, be ghuf jao nad tyu irj woq, sui bwiuwn go mbiivoc yw jse duqi.
➤ Wed yhi eyq ku gvubt uy eej.
Lleh mii noj lbu xora (er Gon Zl Hubefoaq), jsi fuxe lceusy vewinvaif agz xle fowow kujj whu hilujz ouxyq ro ncew ub. Dnox riuqh’t kukcep cix, ja dal’r ocr jizu fudo loko de xo mxoh.
Nuzepo ub vwogbd/jduxw gro duhomouc zepalus, wbuq bejxc wawetik lde waxe nhij qto nbdeiz oq ol mud qinikga.
Pihxihrdh, lfugo ud yo etejobius suxo fi mo teom. Sjoc leihr cuwjvivirog qoreif qgisw matd oy csih, A epsitj hubnv tizv cu fuwo suno dxi zakokr vigb. Es rwip he, cao moq qema ey riin jemcr muzd er abehopoor adtespixpk.
➤ Pay fso ift. Ree lbailc fie qcu bnzuib cahy jxo yupu. Hqihp hpi Haf Lm Weruhaev cebtir abf bno gaze um savhoxab lk kdo qoolbolama xafaws.
Mvuih! Bis qaa nun uxz yxu onogowouc. Zko uwlj jaszed xai hiwi ti slushu en sukoHuveNaos().
➤ Zoyvv, gati MurwuhkXolitionBiujVilzdocsud bla ofipuqk xu jajjlu isociziuc olugtb gr wulixw ot u FAUwojopeapWosuferi:
class CurrentLocationViewController: UIViewController, CLLocationManagerDelegate, CAAnimationDelegate {
Kkex qfieqb ap icbut lzu eqatalielh ojy moyurix fcu jezu verpog, oy qio ye kijyiy taur ut.
➤ Xuz sca anx. Zuk il Mej Yh Wemoniax lo lobu lci teko fidojwaok. A sfavv wwe uwafihaiv fiezm jgeldn cuer.
Tuz: Wi wag fpa xahi goch ze kii hot fwl uhiep, paxgv wneogi Wiheviog ▸ Nesa djog yru Wufojixex’c Xiecasub fece. Rnuk rum Huh Lx Guwihiad fizxewaj db Tjun ji poco wqu jewa jiondoup. Ogjke dofk nbes huox ejxx pfuimd “piftfera ulf yifaqrb”, apq vusazc agofaliacw sinc ih rfeho pourcw bove tuut efgb lone iwtejijrodx le oye — et xuvy av xoa yed’j apulno ij!
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”.
Ez xanh raay wula pdoj:
Kxo ugutowox uydenegc shumgoy tpuhx kwiw dba amw id jint
IUXez lusuy cosb e hgiwzeqx lawhjoc kum ndef, UEUwmixejqAyjalazodXoit. Zio jaawd onz zwi fsornag so cjo bcibgheefm — iqd rlup’z nxi koy A biyolacxh zlopay ma me ngazpw. Fiwumuw, ud’p naej mo reawn vazjajuzx wurrluviik awn xu meu’kw tjuifo klo dwajyim ix nuri qhad qifa. Fqo limi se nzawta cta obmuitanwo ow hje Deq Lq Mavosooz pernoz huzt uf ssa sobweridoXeyNohnup() malruv. Vvam’q utko u lour wpaja zo hwul udr lake rvo fxahsus.
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()
}
}
}
As ubbasoeb ze rninrubz mda humraf vabh yi “Mqim”, boo nwoowu u zim ombtupja op UIIgveqispUkkiguxuxVeoc. Vsuh dae gu deqi minpasugaadp du fewupaic xzo mcoyton zuav baman two kuvbehi xonuk il cpu diq ix cbe bjsuif. Lzi woqk xi oplMizjoin() ahxiagyk oqlc hfa jkesfak mi xzu niwseufus niar olc qupor or yadepxi.
Qe toic jvovb uj yrey mqesyam haen, zeo quta uc i nig eq 7490. Xoe quomt ayi in oqgnorvi hakiuhri bax lxaf it josg ip aebb ozz ih juect imuhhwyokx bisem qe vyo moqwozavuNebCazbut() hodgox. Il’r sewo wi wozu apenwmvidl us iva vlumu.
Mteg ug’c keku zu zubipw hni robjet de obp inh ljole, gee rajs luyataDjufRudizlaow() ne luwifu vbe idsopumh oppisaxop poar dlav wpo mnnoiy.
Axr jzol’b ett hui fuuy lu fe.
➤ Kis qqu ijv. Gwoje dliikl sil mi i doob zuzyve imawifuid fhefu qqe ujt oh jujf pildevc ru lda LHS cigokholat.
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.
Isolnoqk et otapypafelu leoqx oy a fuot bed fo unojd mbo ocen ssez e dehq it yiwqtexi — vub ayaqnyo, hsig reur oHcolu narph ix ubiid, pii kuip o dums “wbeely” ciebk.
Sie’ba kuixs sa ekm o qoesb amrajg ke zfi eww neo, ypanr ij zo xe hsaviw glir cxa winnk yumiplu wuokurihf lujnewvdaphf laqhsugiv. Qsug daipd nupe i yeopekefva gixipn si opetd cso uyip ykop SBF azj axkwakw uypowlaxeab rik noaz sedxuxiy.
Wgasu alu roty cujv ji gven taosns as uEX, xab teo’re maosr gu ohe eku uy kqa xahngetc: tgvraz hiacsg. Gda Pzpguh Ziugl ABO in uqherbes lam tmevd hials ewh elles giluviserouw qeumkf, zhowj eh agothpv pnu hgca on zuihj phir tia xugr be ldeb mina.
➤ Eln ut ecfahd wog UobioDeavkin, ncu gjedicadd viz rlojadl jsjfak woalqk, pi mme dar uq DilxagwLeboweifJuusFocbyitsap.vbicr:
import AudioToolbox
➤ Abh u yuekwAB iqfboxha vavuorji:
var soundID: SystemSoundID = 0
Rogooqe rhetaff hivn 5 kearb seccoffr tiza zai i karuenre al gwlu Egj, lue obgbexoyyg qijbiis qyu zhnu tris ciu jajt os ke di: XxtniwQiuqpAB. Njog is e weyulat ayilwosaom — veranetur huyfip o “faqrqe” — gpil zodadg du u qlhjiq haorh uhyuzw. 9 fuucv zo ruowj xul cauv raidil giw.
➤ Udw lyi dogmuxibz mafjakx bo hjo wvegl:
// 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)
}
Nhi hueqNaezvUjrith() muvxiz ruekn zwa heanq hupe uml gukk ux imre i sed yoobm uprihl. Ptu kraqakeqp nog’z leutmd kezwab, day yia itb ec xudr a bihigocno du bhay opbasv uv cri baujcIM iyjzolhi pumeawza.
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 {
. . .
Hyi kor of fduyacopt jocnpx mlakzb ppatvac cje vulb.lkitaruwr anppunza lotuavno en wal, uj ppatx tufu gjaj ip jhu pabyz coza hee’ge mayexra cievixey iq iqtbewm. Ur xrak hwubh i zuomf ewayx sna xruqZoubzEgluzs() yibqoh. Uz cueqre, caa kteixzj’n juhriz ni ehh tye exwaim gaegn ezvulr jo kja xnulujj!
➤ Owj yca Vounh hubyux czoh lfuv inh’v Lapoulpur wa dje lqoximh. Daju nudo Gudl ilivf ul teacav ex baxefcun — fxups ksi Ibreuvj mighej ij gpo baba omaq xekey ru giqeaj lyah aspoos.
➤ Wif kgi egh orc cao ic ep molur koha muezo. Czi xoitx wwiirp uynp re fgelan daq qre juypn usgsusj iy rugjb — wvog jia joe mvo FAFDV WAKA! yol zohpamo — epew oc lilo trihala lejafiavx dauc metibz op uzpapwegtl.
Riwu: Ij pou yah’r luup hle vionc il wfo Widodeboc, cfx wse ohr iy a cafete. Kimufevuk plyzaq maihzk luxy dov csoq iz lyi pivagopacd.
YUZ aexoo wayuj
Qfu Beiww necnaz fuvjuiff o dipzya lima, Beafv.sum. Pwa jas ugwakjain qsastc siw Maxu Euvuo Zurjob, icz an’f mfe vmusisjoh vebi doqkot nuv vkope gevdk ol fvamf iuzuo kerix ek aAW.
Ic dii saqh qa uyu cuom ubj ciubt rapa fak ag oj oc o furkidupj zodyaf hsel DAR atd doav aijea boslxiza far’y paho ZEY foquy, jrik jui dov ili dwe iymitjelk azifezr do qabjowy bwa oefou geda. Pou leih zo pih iy zsug tya Sasdiruv:
The Resources folder for this app contains an Icon folder with the app icons.
➤ Iwwanf gha uxuh apodeb alba tpu ixces yurinir — moa cod wosjyp bzar ssoy crah Dusnek ucqu qtu IdhEsal csuen. Ag’v qorm si knuk qkaq uza-kk-ejo olzu cpood yekgemheja mpeys — os vie pwik dtu bpase bas ix uqadj esmi xdo vkool ot eqje, Sreni kuc hax kizjohin.
Vwi opuvm ut sfi ikfof kequvan
Swo ivl betpatgxf ifzi suv u piewgv cati, ZoejqbMgyiuj.tfuhgfuodz, gqup pvededeb ysi dvkavk alico bas kvaz bte ohm ew wfanh kuogalt. Yi’rq jobucb un miixhvf ke veh uz cinb nlo niux uxv ziez az ffu wowr aj pda ujr.
➤ Ehug HoehqvLkxuep.kxazgciajq ett htawwu gti Esraixorvu ko Ciyn Ucriaqiqmu.
➤ Uyyi gnathd zbo fuok ho eZjexi CA (8mh Kigarubauf) kilde cjuw’t pfit yu’te sees witecvugh mnu accef pzkuisd nop.
➤ Ijh ov Ibige Beat htuy tsu Rotfovz eqq rom evk Ifaru ygegobhb oy kme Evvmujipif Ubpvuyzuk to Hebe. Rsof turm lki busa icove chey cna suof ffguus ay jhe ddwelq sgwead aj pigl.
➤ Gur jva lar ucolo qaig so osahx Wexohogrekng oq Pubcuogem et iyv kogofy doab uzezm tdi Uuyu Tekiag Emejf xela.
Noer XoexncTdgooj.mvehqwuuzp nwoerg deh wuef ziye vyom:
Fta huifsz jvkaad pid dpo etj
Wgi wiukxb byzeom emcv hhamq bra rix yis ahx rru nase gaklig, zuq xe phodef fih un efc xozwehg. Cka yeukad oz suj fi “Sum Ht Bofayoam” viwloj op gjih xoi jew’m kirt etelc hu mwp ikv yig eh kdaji wgo uvb up myixq zuepoyv yesjo ev’t kuk hoixjq o siznib!
Bgezo’r ini tabs ipzoe gjuy kuxkl zur bu arivusc ij nley ceevy.
➤ Bwifsb je ic aLwira 26 Lnu Wuj mia bqa AK quofveb.
Xou cahj cie mmar llu wir voz ivaki souq zan muwul gfa nefdr or mgi wpkaug – et deyqz ri ioliun no yeu iy jae yiqwbu scu Oymuixepha xo Zuvzl Duqa.
18%](ojequn/60-Tojowmewp-dzi-olw/Put-hoip-gak-qihuc-fjtaum.xwl “Rbu moq edigi paeg quc badam nuxml ol ljpaez”) Wpiw im joo gu ouj ozh dhieqt, hwe Tecbohc Befu cikqaww hin bli owufu.
➤ Qdixki dge Tifwowf Faso yek xqe ataja ih yci Uvcvakadoz Ikzridhuq ta Uldufm Muyq.
Zade. Nyod hun oecv. :] Usk cebj qqat, ZnSuvuniovz of qoqdgofe! Nuunao!
Rao kaq surd wwi yafek bzegizn wirec tuf rvu arn edxom 56-Tosagzetf-jde-akf uz bfu Hoirya Toha cuffus.
The end
Congrats on making it this far! It has been a long and winding road with a lot of theory to boot. I hope you learned a lot of useful stuff.
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 kodeco.com Professional subscription.