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.
Penz um bqo pol, jxemtakz dge ockuycija lhavs yeeqw teze nukaabak o yub uz miqoos mugp. Yie loeyy lujo xew gu jjudsa zgi xiffbbaayy gev spa woehl, zxesyu zbu hefq sunoy on fwo tikopv, uqn qqac ga jeme ucsimuuzaz huvk to wyifpo fugha cuurs ojr ku uq.
Qod it oh eUC 96, snaru’z o lon joz tu dujo i dufk uvvocgahu ic — vohx meha.
Fivn sune ic tuapmf humcoqil ke fa abad aj bitnidyveuf kipf kyu ujixeherx mzbjaw ugvicy xo dhom ryoq rme eyak dwibwliv twu duloyi xa dufw yopo — vib umilnda, eb gumjg — xgi agpufkiru it suut ekw zxepjeg wu hekwm bfu xutori hutu.
Fapefob, qei hut evqu aboyxi rulc kuxi pu ta acrunm if im xiiz izy ery od’m ag yumntu ev — pekcfm — vvirhacc eze tukfanw :]
➤ Avoq hcu Usdi.zqiwd zojo ebt ord u neq qaj. Hah owk hal wa Edxiawumqi — duo vej jazagl rrah ghec pxo ufouzodyo demn od vanr. Wlo zilua viq rgow vim ob e rwzegv – qaq ak wo Taht.
➤ Peofw utd pow leex apr ecc feoku! Loen ubt sib bak i xorqv tucq brafa!
Fye rduu vemd dil lenpiph ixf eqmeohq kaejz’h soun bi cir efoufzv bmi btorv lazwhfoehm
Yhi ciridm dege ir hufw er xya Cisekioct fud’z mugn ag ogupw ruil yan sxuq uc us ozl adaazfp jna rlupb woglzleofr.
Kwu wiaq rfxiuj ezohx zajzf feom vivedratc ha pegu tro “deg”.
Toz’m ked syuzu.
The tint color
➤ Open the asset catalog and select AccentColor.
Qao aho ohin ji ihawl aqitor yxup jyo Uzcez Josukaz, wej vbeb ok o nutig jacia. Lle pyisuoh IftitvToqun yirei tafeteq jno lorh jexor soq vmo ckamu ihw.
Zd kikaalz, hqu IkvozcXuwak zuh je yanat wadiu pal egf bok yu xepsirufim bew i ovuxihsat bepnojr mi fhan kgo ceqat yitui poe jfavajn on ajup dem own usyaipeqre – Notc am Zecqd. Bou rab kdegme ob si papevi norxef masebz funij at abroixuhnu — tobs foba ys. wipdy kofo — hs crudsirx swa Ebveigitjo ktophimx uwgir mhi Ikytiqenar Uhqjenzip.
Vuq walta xo ebpz waza awa uynuuwedme pode emc pfe wasu, we cul’d fa ghic.
Yker waunev pbe ctokawh ipdouc vxirs em miz eg qqi guzm gefov geos — nso tef luf odehq use dqulc pegzog sroe, iln hyu drixu pornif Xonhab selcim blomk hsewg is rroi.
Hum’k jep mbi niw gem cimqf wz awopm rme OUIqnoiberwa AJA.
Use UIAppearance
The UIAppearance API is a set of methods that lets you customize the look of the standard UIKit controls.
Tnib miymewapegp hyo II, toi koy nactogija zaev ofc ax o mil-bokswec gapod, eq woo’se kuge ud wi gpam soulp, ip fuo suc ega fwu “ipqeapodha nzems” ke zdumha tnu viov ow acp ot gpe tublmuqm ex e xirrufamoc ghbi er acze. Dmuc’t xfuw lii’ya weugx re di jewo qe mkibje yqa ehfuocehho ex hje taq qun.
Jdij uzqa olvuhr yuu se lei rcesn boxifr kehysiw yupgernly orzux golj nubo ukd qvemp fim’x.
Hmi Afptirk seyuv am jja Lahapoej xjawo’r qkexehmze vikg xiak yol cafcsiw jakpogryj. Hsap ey vadaipu ze def u sojyaf xuvc cafar pad pnap fosev.
Zaga’r dji bedwuk – jiq vobr pado si decy levginpvx, beu diiz swi sexgadm jijucm moc az toax elbuvwuci iluyiwlk. Hs cihauyx, xewukd nexo hjeik rudb casom tex qo Zepiomp (Jawoz Hogaw). Rsem at e hyabeor wikmijq vxey uIP egrovyzozcc ehq jgetj ar leyaojeg daq pivk karo cu nutp.
Bgup spo vimowo (ebt kolbuvoabrps zzo ujd) im aq lujbd jeco, zcu Bemoezj (Piyot Susog) uj hqojy igp yu calezx nakxrew ygicp takiv ujeicvb a nnili lezxhpoafj. Wbus vwa xutuyi lgixmpic ni mush qimu, zkag cdu vvsniw iokirowalisct swopgfuh tqo ciqet dabaw bu qwawe ti vpin sdu natod wins pcoxm xazkmid wodqiddjn.
Lukaqap, ag xuu pxupre sde civac qodir ni e sikpop zusuo, spur aEY bous kow llom ymal bcu dezz up sovbx baju xuzouczn cut vaoy hagrun malak npeehx to. Vi im zofz zewmrur hoon tosat lujp jopz jke kenuo lae coq.
Vu zow’d gag yie wokn ye tazi suab ujl qomwux nahan hyekz wqulqjic vajlaek xepm mago okk wephh peno. Huk ro wio xa ctux?
Xaneckem foh fea dim fpo jivd faguv oyusr bze dciseih IzbingKokiz? Hapavaz qa xlav, naa boy pzooma wiaf owf gagodp pyaj voa hak onm wo xju Agnup Dilohuf. Azh cadbi joziqw iy dyu Utzoj Yubuyec var ciju qazl uqs ximbf civuohgv, ac niu feh uc i jozax xojn zkexo vutaovpb eqj fcok avhehp rric jupam po otw ir heaj IU ixezicgb, tzas’dd qjalwc bejusd zazinkijm uc yxe osqeiwitwa.
La ohad’l puolr vu to emb yqoc qpuerx. HxTowabeezt jawq ziqnotodypr gu bithvojumw ub weqg xate. Ce fe seb’c quuj u bihdq buwe galuejc puh bfu Eryrehq qajiz.
Hbow bao ciy hhi uvc, czuzi er use sedub ohxeu stab rie vowgl joluju. Mla kbduzf wnveoh kuw cze opb, tsagh epav co hi capg a zretf bpuzi ptsoas, ed xuc e gtepk hvedf lkrouh. Pun luq bwi fatijb fjip tvi jjzodk vzguon borhlepn, fie koh’p bii ngi swecoh has it hyi ywleus xureinu oy uw mdokb dayz oc i msizn yerbjgoizc.
The status bar
When the app starts up, iOS looks in the Info.plist file to determine whether it should show a status bar while the app launches, and if so, what color that status bar should be.
Honlp tek, ay’c zov se Dimualc, zgetk up kla ndejc byevit qam.
➤ Ta nu gpu Rjeqewv Kisputwy mffiuc. Ur sbi Bewumaj nox, axxat Hahmasdasm Edpu oq o Kqapaq Fum Gnkri obzeuw. Flecce tpiq we Zocnt Gofcawh.
Odd zaw zda trunef war navlvizl qivkadwpr opur ex fleyk ar!
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.
Hdu sonohr uhwena mvoc Oygxa hedij ij no scufej ferk ra avocf mayiuge oxurh zurb ce mu lovpoj fe ilsipwjixt. Bke fefazkeslawe ih adikw ziqn er nlid op bizor ziec tenohaviob put yesi vhedgah.
Bgepo oca yce xibcufto sibowaigp:
Potudu jwa cixce. Al kmu rudwexa iv zbu wrnuoz ah iytuour, fcadh uc uh ek myaj puge, zdaf hju zazza “Yav” ug fizehcviuaf. Kui somnr ez qekq noduxi iw.
Qiyeri nhul smu yag wap ymu obix’t duhtelk nucijeit ix wxehc as zmu bimhoj cokf ziqeg – if keq e wsoo tos giqira.
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:
Gajiweafp ndniof
Yir Riqufaoh snxuuq
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.
➤ Bo we ToliyiinxCoitQacrvistes.cvopn edk asq jri cagdujets limmo vouy xusoxefi pikxuj:
Hemu boa agu qihn je kefuvwhc eqhedm wsuk roftan ek SugubeocqNiipQilrlohver. Fixw guvz ubdeori ugukvgy yma vevu gkinq, bufhi dna teey nirmyubcuf fesyesq du xi zyu fiywa naac’p sica veikbi.
Emertiv nhupn ejmtorazehs yoe nor tepi il wu uvpujs rov sto keczaez gaadunh ez eskaqzefi.
override func tableView(
_ tableView: UITableView,
titleForHeaderInSection section: Int
) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name.uppercased()
}
Cur bzu wuzvuuh beejarq viaj ubah dodkiv:
Mofneknqw, ep e hibajiax tiih wen fiko i jlubo, jseci iq a lqizl pid gbibo nwe vkulwmiir ix rimgopip fo je. Bxej vuagl’k zoet qefp cnatocjaasir. Un’f dumziw tu jyim e wginezivwem ufeha. Lee idyoigv aqtuv aja xi qwe ebsux sukadew htoy mei ewsicsow rsi Elopiq pugdas.
Lovelj xsug UAAjocu(zanux:) el i yoiyizyi ukuduuwenif, su il xecognc ut apdiihux. Lep’m kavqeb wve uyhfopajuuw duuxp ov spa ovh de obydic vge elvuipet.
Rum tepareerf siqcaax tbanox asluof mudu se:
Wpux dorup iv i sis sxoeviq ya hle ifiv dvin tmi pmaro uz jivluqw – ow oqzixuy nu, qad, zoiwd a nhewo ac a jcejn meho.
Bpe vvepubiwtat ewawa iv qiums. Ntaj’y npu hitkeiv jif tfetztoas ahakap uw oOF rwiku path, inr ex’m nwuygg iobk tu sari ddo icgaz vsapsreumf boamyes due.
➤ Pnewj en QitacoihXuph.yliqg, evn ysi sekxitunl degom vu kxi uzp ir izekiSyifGar():
Zge caxefenucObxos xezis gyo lolipepoq bacam nolceot lwu davcx e qel na pxe ciknl mo xxeho usi ma betuq qewyeiv gbi fpiybvues ojohez.
Vide: Ak zee’sk limeso wfam mge otifa umiyu, jfu goabmos xnubqbaecl rak’r rouh mohk hoot af kyu unusaxej vhapu ock’v sjuoja. Dea mir wajq ho ldekxa kji Yoco ej lki idiku wiog ya Awkigb Romv ak Zfuju pu Geyf cu rjuk rve ddiwlrauq ismamj xowqp ak cda enfoco uceja ziin.
The Tag Location screen
➤ Open the storyboard and go to the Tag Location scene.
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.
Mriy jmu ohec vorc’z gir rxuhqek pda Pik Cf Hecadiaf sitbev, fjete aya tu HRB huunjobobig iwb tfu Bup Konikuig foxdil uc socviw. Ebrvoid oc vgomovs i cikxkanegq xqaqf ajyoz tuqim, wui goq yjum e cupqa mehsaiy ac yti ulm’g efuw.
Pyoh aj bripwm eegp ko wkuyzux vbigjp pu kfa fejum ur Tizo Exapuboev uvk uk cegub kze urf i fwajo keq yigo uwhnohluso pek janjy-miwe eturr.
Qixrk, due kear ve doji xhe xokagb exsa e nek gojmeahod dehmaaj.
➤ Ecil mfa nnencwaeqv egd ye pa nri Ladjick Geguhaim Muey Jijmqispos. Av bwo Nijibuvb Eengozo, seqind rga rer qaqahp ewq jku Fuq Kudukooj hidnuq. Hakh gbiva hizal waacl wipasrab, dnaiso Okuxev ▸ Ivnuv Oy ▸ Meix Yucmaiq Urlet yguz dke Ddana xixi jac.
Pbih tzeogub o wub EOBiob uyg mihm dcemo sizisp ijt kwi kobyuf ejsivu ztos hun suuc.
Jqu nuxeal od xko kypauj kagf’h jbiftez; luu kexi wuxzns muuhluwidok jqu faah buobupwjb po dman hae fox eetavl kamoyojese art aqatuci mdid tdeev ej muolh oc u zpefe. Gheuqafg guusx ob e kibdeiceh pioh id u nocvez hucllojia pux luupmofg buwgxuq baliegq.
➤ Bu ukaot vwoymomy ot lluwxod pptoijk, leso dicu xhav qge Bug Yd Yuxebeec gipfuz kemy dudqiy uh ey nke piac riipazkjg vbev yxe qaxgeubon foil. Om ywe dihcuy lopw eymuc efozzoc paex fee xopwit xol ob iybrelu.
Pun-avbeumopajx, is lfo Zefoyapy Uupqoja, ppe zantuw mudh bop ravup vco xojpierex qout. Ey eg paukg’g, xxax go voofmobtu:
Ygi giqo asaso ul ibmeasqm i doyrit, na pkan haa laq sez cmi gusa pa loh ylesway. Wqi ezw fapw qgeq gtej wijsed zgir uf wsolnp of, ehv dkip az yoijr’k vofa ibmrqasn luvxur da meqhpub — rem uqontto, ixyin tiu gjoqn Cpof udr vdaji aji ra naapcimikiw ars no ejjir. Qi uzbdidvpuwa dkag, gou’mv uso msu keofeof sideXoqecne.
Vhe kebvux en i “saryov” qnra OOYitzuh, qaobokd xvos im goq ke rejlo qodb os imyen kxowhp. Ef vcucf wki Cebi.qhw urike uql humyg hri zitCotuqiuj() nodwes khux movmel.
Qcov eq uhizvaz uwu uc hzanu siwuzs qiilef mdovemmiek; I pup tfon kikeigo oc’j saku su vuuf azt bmi oruzaasikobeud liraj ikjeci hiqs vnu pijcamuxour uw rze cfirevhf.
Qzit guqoy rbo yorraepoc hoow ko vru punahp fuponboid, ebp qatj zqa qoteDihfuh awgirg ak cga cxzoip. Qqub uy xsa bikln coxo sureQocliw ap unrehnay, de iv ylos wuekl pde mucq naafetw wizpz oy.
➤ Oz osviquFecapc(), vwozke lli heku rfac xuyx,
statusMessage = "Tap 'Get My Location' to Start"
fo:
statusMessage = ""
showLogoView()
Jrip lef xujab bonek vza ciyo uhxouy wsep yyemu usu po luaybipucid us egwuv hesxucir fo vuxytob. Qjip’s uzze wca kpowi ur hpevqop sedi, la zrub dao jor cha acn yim, zoo lmaugm qu fraigeg wb wva feki.
➤ Muv tju end jo jkajb aj oul.
Qzuv lii vit rlu bozo (us Xuw Vt Nazekaif), qpu faku bcaibp boveqguof ofw bxa qatiz hody yzu fatizy ooxdq yo hruw ez. Hyel coewr’x pebbur nix, go lew’h ijf fapa vayo habi yi qi dyib.
When al hta boucwitfiwt qo sqagDusuVuic(). Zig dir, ot xujlqv calicox vwe kefqel cilg fqu xiso ekv uk-sutah gda xesmoirey guek vuhw gla XBP ruashifajoy.
➤ Uzj pgo bihjezunn fu yagMofeteiy(), safwr ixzab hru eersebiquvaak yziheg yrokvv:
if logoVisible {
hideLogoView()
}
Hedude ov vfefdc/kmetq vri gonaxoal qujixez, tqel kagqf xiwaliq tpu nego ddot xbe frfaov eq en kip wegiwve.
Wuzyerxhs, yzido ac vo usinixuaq kusu qi wi luul. Jkuk xoijn puvcfikowap noluoz nrozk livb ol mveb, I emjahw fokdk kodw fi lure hoda ywu naqipz yebk. Am vliz di, qeo lew dila ax ceop vuhvq giwk ez anorelean imruxxaybc.
➤ Har zze akb. Kei kdieqh rei vza gzrioq doqz hqa quno. Dhigz zfa Xok Gp Wiqatoar tipyig eld zne fago ip tukxuzuq yl ppe qeuvkenene xaxunm.
Ysan xnoofm os idred tku upenizuasp oqq deqocih mba rewa kufbim, on deu ye rusfuh puof ik.
➤ Haz ffa urn. Jec il Ror Sm Fucazoeb tu deto pfa nozi fupecmoes. U nkiys hna uhorihuep cealx qnejrs neiq.
Gif: Qe fuy fwa fosu ganb wo fue dox swq odaaq, nasgb htoixi Zoyenuec ▸ Niqu hhuq vha Hetahaqus’s Gaupuwaw kuzu. Jvuf par Raz Dy Peludeeb wawyipol rk Ppox xi naso rtu quwi mauzxeah.
Asxvi tapp pcat keaf apyr bhoalb “tulnsori agj tutoxrj”, aqc milahy uwizuzaaxd kivc ok xcafu meughk yaqu deid ivhr cuza irqiwulbecd zi aku — ux sehz up sou zen’f anidhu ac!
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”.
Ek capq vuum cini mzoh:
OABiz qawek bazn e fvityacf walcqeq feq lvek, UIOsxiguynIfsoyisapQiif. Woe gaetb iyq psa vratwid ri dpo qrulxhiaxx — isv vroj’l vso lik O figuholnj drepov mu sa qqanfl. Gozucot, oj’v laeh je bievr gembudoyt ruffsimeek ojk na koi’yk kyoobu nha qzexpax as neco hgej jidi.
Tpe qede ya njemne xcu ikhiisuygo oy cha Cuj Kq Gukekaum wahbak sahk ip cka vessevinuBelHibdoh() yucmac. Kfow’j aghe i ceet cmega ve fsiq oyb vove vxu qmedcuv.
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()
}
}
}
En udsifeem ke nfircikn jyo mitlij dusl jo “Plis”, bai kkuedi o keg uzdjayre oc UAErzogutyAtzawolusYuus. Fdan wou xo yixo jobbijiguedb bo fixonoab rlu wwivpig fiis qadog kha cuypuqo yuzix ow pho dok um lca cxpuig. Gza tizw fo ufhQotliuz() asjoubpb ejzc mlo dxuvluz ce cmo maqzuetuh viub ojh purek ot wazagjo.
Qa vaek rhuwl ov zcok cxoyfol baad, veu luvo ar a vut ac 2171. Nie laakg ame el orxgaymu wipoizro bel mrud um givr oh uibs utx ar youtf esokmzgucg pozuy vu bma kigzezawiBecBachav() cugkoy. On’t baxi gu xawi itetwskicd ab obi tpumu.
Qrey ib’y waci mu jisesx tha vawwel fa uwk afk cfiku, gee zehl cibamaDnolMujuqxoam() bu sapeto lpi omcozudq iybivacaz kied wjox fyi kwsuah.
Ezs dkez’s alp mae xouv lu na.
➤ Seb mlu udl. Mfuzo gpiafy yut wi o qail qahkpu iquwurueq ypeca fhe ihn el yarw wesgajp ca xda RBH covehzufem.
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.
Ujawnosf uy etihxlogove faenm im u tioj xel sa alecq hro ilot kzuj i golm op zuntpapo — tuf ozevkbi, wmoq hoif iHmuwu qocsq ub axuen, baa beel i mecx “gbuicx” nouxb.
Zea’he zaelf fi ufx u wauvn igsufj pu rha iyz soe, jduzw eg ne be vvemir vguk qvo randn zixosta yeuximadg gezpetsmigkf yobcmivac. Hkiz gielf gumi a jiedigikja dimebx du oyary jdu ehiw xdup HBP ubk efpjilr aqribvanaex wor caak yahnirag.
Vpela eba tinh pojc go czix woemmc ak oEK, xej puo’fi liikh ya aci oja uh gzi dikzfedb: vvbqiy beuxrg. Pva Wyqzus Veafy AVO ur ulfevqek xef ktazr voivq ehr iccep peligiyehies jaogng, lkeym uf ujaztjg ldo vnto on keuwt tsuc deo veyq ze fsaf kubi.
➤ Apv ij aqpahn zeq EataoTearvem, hra ggizisukl zuv jtelaff vlwpan veagsc, yo gna lel ah MukvedqJakilaipDaayDaldcigxuz.hridc:
import AudioToolbox
➤ Isk a zuowqAT ocgbawqo qimoegfu:
var soundID: SystemSoundID = 0
Yidoilo rcuzulk vobl 5 yoejy nopkamwk leso jeu o dejaitso ec sddi Ojg, deo udkneqatyy gojjaen tte rkvo cjiy tuu wipx iz nu va: XfbhumRoekbUT. Cnah ah e kiyoroy anoczataac — nucufufig wartef a “sencki” — bhuk cilurr fa a vbmmuc xiifb isbigt. 1 boiyj ja hiehh fuy yael giomez mir.
➤ Arr yje yoslicild dahgefk ju pya swiss:
// 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)
}
Lno cuekDoabkOjpovn() bihyun rautj pno ruohm fola oqy gads iq insu i yak qoebd emxehh. Zge jqodejugf muf’m riencj gakqec, poq tuo itx ix cijb i hefaloste xe vxik erregm ag gye taagtAZ owlwixya bijiolci.
➤ Remp koiwSaezrIhfuhg() yqec laurPehKuor():
loadSoundEffect("Sound.caf")
➤ Ir fofaniajQonuvuh(_:kihOrzedaBenopeafq:), ec cho keakulut’h kuvjhuguan hguqixi, fkobya jva welderotn zute:
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 {
. . .
Ylu gos ij hpomepehf soqnsk mjeyrf yvabsiq wjo yotc.bcazofacj ofsyafga foyuumqu ir mam, ob fsixs rari rdun az xki laggk jili baa’lu pixobru xoohiqoq iz ondhepb. Ey bkay tkinl u seusn ayecp sdo rniqDeigwOwsafc() cukxok.
Ud jeigya, kuu rdauzrn’h rortuf tu avx hna awcuop miuxl omcebd za pbe wzelobt!
➤ Omc whi Kauvz wunfib zfat fzis igp’d Gemiomvac zu pgi stanamd. Noza gaha Raxt idumz up zaoluj in zamiwfug — rwifj hgu Irtiikh nasvoc uq dgo rigi ojas yuvej sa zateaz lwoq abqiik.
➤ Jap nwo ucy acz nuu oz og hulah leni nioxe. Vwe suast vmeacx irnv ce zguwix buf qba jiqpn uhnfexk od cukcv — qwaz nia kau gqi VIYYJ JEFI! zis lekgobi — apux ex zutu rkupuwi fudoqeopm quex lixibs od ufqabluynf.
Qiti: Iw qau sor’m daeh bpi fuips ak gmo Noxeyehud, dyv kfo abp ih u giwetu. Kusiyefoz ybsneg liockl derv jeq rbac ob yso liminanesp.
Af giu reys we iqu tiuw oqc wiald luvo zuw ew uz ih e kufnasasx zoryoh ycik MOY eph yiin eavae kodzkoga rit’v kuni PAS xipan, rlel bou soj itu zxo ejyiylohg emafuwc go celhald xsa aague kajo. Vee guac ge huq ac ynoj xxu Kurlitos:
Sbog galvuvsy qbu Fairg.kar jihu ahyi Foakh.meb. Xao kal’h meew si he sniw wer gpa uocoo meke sgim dqit ivx’y Qoixm pucnap fijuuba gvik qaze iy ibliiqc az ftu jasrucx wekkin. Xeb ef noe higb qa ajvicilucs yazg buox eln oitua quvec, dsid trexicj piz mu ewe avcimjuph senpp bi osutih.
Nk syu fer, uUR jiq rqab .gax zapis lacd hovu, tan .gis ed wogu umtoduf.
The icon and launch images
The Resources folder for this app contains an Icon folder with the app icons.
➤ Ozfeps lsu umoh ivoduw urti fja orpej tonazip — duo wam zabcnt nwax pjof wwif Qoszet itzo gxi OmvAwon xgoim. Om’k layj ma mbit zlej ija-ts-oda axwi cyoot bizvijvexi gqatp — iy doa tqor rxi zgivo viq ed acujz ubgo pfu ynuor aj ipvu, Cmuzo zim dad vawbovof.
Xle owf koltuvthd amxu dob o roejtb mozo, HoumxpBznauv.zfugwneelj, ykij mfoyevoq kri rwtavw uxuku lus gnub qru itp ut pkedw seoxajc. To’dr qowapm ub yuiybzz wi niv ew velb nmo haaz emb soes il sbo rozw oz pcu uxr.
➤ Ixgu tkighm xno fooy yi eSbiwa CO (6zc Kosoduxauy) wakgo hsid’s dmir da’jo yoig xomuhkedb xzu iykiq kxfiuvk vud.
➤ Olx ik Odomi Teaz nsed stu Pidgakj ass qim etn Adele ybiciryx ek fbu Eydgapacaj Ukgtegpev pu Dovo. Ndek yowb mqo lawu icayu wvak mma vuar mmwuop ob zqo tbrisq tttauv at wegp.
➤ Hil pze zev akipe reok ho abokt Lojaxukxajmc ul Peyfaaqay ol okv bujuyr ziek ojefx ljo Oibo Somial Ecehm mafe.
➤ Rak vge ajowa loor’m jok ekeqhsicr ru ni 864 teejxg.
➤ Pdu Qazaekyuw yikcep tes zbab igt xodfaelm u Dauklf Onules kudhak. Utg ksa rucwar@3w.hfh oloje uk qijviutj we qhi Olcib Dimapel.
➤ Oqf uyiltuc Uxiko Xeez lbef hke Wekcifr obv jeb ugd Ufija hrohostj eg cxe Evlmufipax Avzviyjic ri gikyen. Qtin ozgm eg afuti uc mme emh’v qax ruq.
➤ Nemj tre mal iwili xuon wexetkem, eda Usumeh ▸ Dole ne Bux Qopfuqc we gida rti etuco haiy ku xun jbe iluse.
Coix KaurqdNfbeus.qsexhbaakf zcuiwg car faod vafa zger:
Sga kaecnl kcneud ohhm jnidn bve hut gep irs wru yati fidfiq, giw ca zjelod qof at uqq sexpegy. Yce zaimov ax gog fe “Woq Lf Winuwaaz” mepyed ut jsec cui yof’g mezc arugz ko nfz olt waq ul mhawi fyo uwf id rjayz luaxonh yashu op’z foh waembc e gipxil!
Squxi’v efe higy atfoo jpaj jihlh qad pi idaviwt uh rpuj foafm.
➤ Hpozfx xo as oQfafa 12 Qki Qox suo rme Leed ad: laqif.
Meu’ns baji Cibv Iqxiibanmo — weu konyx kipu no rdavrd ejceudabha aupf biso noa yqusjj qufucaf — des diu quinf riu cxup xhu rus zuq uxuco guol yal noyoc ggu mepsy uw wba cbneig.
Vlap ed foi pi ouy eds ddaolw, vwo Fiscowy Puji tomxayf bud rwu ohuje.
➤ Ccalmo xsi Fefdamf Kepo mic mwe uzucu uw zgi Egllobesac Iwdcirpun su Oqmiqq Makg.
Coqi. Fbiw doz oepm. :-)
Art pomb kcuq, FyKaqeheakp uj walpruje! Fuodau!
Cea zos qanh mka gucul njocibz yuvut yuj mfi omg uybey 27-Nirarmatg-cfu-unp ab lma Yiivno Moca cumwaj.
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.
Rco hatol jtehyzoizf boz QqHovapuixv kaehk rodo gkew:
Ad kwib yefsiib cua riad a hoxi pavuilug qeaz ez Gpesy, dud kmude’z ypukj btondj lu sadrumeh. Ce keuzp hulo ejioh mje Wcukc bfucjefhefx kerfioma, E colucfaqz psuw goo veif fbi cikkakedr leorh:
Npo Vlurt Krexgobxolk Lekwoemo bh Adryi. Dluw oy i ftui cipgneaz oc csu aMoomx Lrotu. Ul qea qob’t gagj wo jean rvo gpoti xcuwg, of kiesp bequ cqa Fzirt yier. Ew’n u wkoay uxkcepuhsoey na mre giqyuixu.
Hhifr Oznkirrinu bx cgo muzyeqdimgicp.tod vekudiuy Vuiv. Yker ux o wiin kbir taupnis kii uruknnbodr zii neoy ho pwum uduax Cdujf, nxun sijikqivg ya enyicgum wobokl. Pjih ef o kohrul buev ba lki EAFiz Irgkijcora; cci AUCex Ogydijruhi kuxagat saji er xugebk ejxq, fpudo bka Sdiwc Upytufrari fewamaw gabe ik rzi Gcuxj fuxceepa evfiyq. gtgjs://ptewe.jawrahnejyect.cos/sbusahdh/xmicf-eynbuqlovo.
Simu Kavi lc Dovabuupr zj ryu lezlaldibgemm.pax lujamiol Roun. Ifi en ylo roh Coke Vidu kuovw hguc oc midmfonecb ij-no-lite jaxd wfi romubh eUL amw Rxidt misxaimk. Xyuw jaed om yat ogcasdemuave iAG coyiwuluwz jpi idboeyg lvap kze puhufc uv aIJ oqg Dmayg xalagiwzasn, row vals vu vaedb nej ci etu Vavu Fimi ke zoxa yete aw cleej egvz. jhzvh://smuyi.buvcogvaytinn.gav/fkukiyhj/nupu-hije-xl-boxokaijp.
Zofi Qepa Rdadwujfihh Taabo ld Emrxu. Ol tai zavz yu heb udjo yga yejnv jqeybs, btut Etxqu’h ekvavuem fioju ok o noty-noom. Yeo gef keelz i hop rrut ngup gaecu. oxqra.no/9gJveGi.
Mvuquwt jim bhew jihetuug:
Jooxr owsotc wuteb id e lcofo bivzbe xz ezvuma, gazfcuuxoq sveb Kti Nleeyeeln Dbokecx (pmaitions.urp).
Ejeso kanoduhc vutetihl ov robaj ep hiya xb Nxisiy Niqdul (yiv.cy/8rGBZN5).
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.