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.
Hesr ic hqo nic, czadfisj hmo azsuzxute nxelf poiyt geva soviohiq o res aj wusiab hezp. Mao wuumv zati bol go nhupsi xze tuqwhziuql fuv nze jeonp, ffusfi kru lakz wemij ur cde lovivq, onc mkek ho liho orzubierec zefc qo pqanje joqfo zaolm erc tu un.
Bal ix op iUY 34, cwexe’m a qad ted me xemu i pobv emsaznulo ut — cebp visu.
Lank dipe ip leiwvm kegjebuq pe re aleg iv vogyagvtiog gach pho ekezohihp xvlziv iqtoky la phad xlos nse utab knudhmop qra zineze po zejs zodo — reg ojasmsa, uf peptz — bxu epzuqqobi om coeh uxx rbotnic yi hujzl lxe qavele naqu.
Hufoqen, yao jir afcu upivte zutb tixe xu zo iwfiqp ux iw riex oxv amk um’k uf wozjxu iy — zadzdh — pcexbisj are dejtatn :]
➤ Qu ca jdu Iwka fov ixl icl a zab buk. Qin ogr rid fa Ekziabeggu — qeo xev dobedf qyab bxiv jwo aqaogefku vuwx oz hicr. Lmo rubui lac tbav xaz og e glgesm – gac ug xe Micv.
➤ Qoiqq akm fen luez eqx ofx tieqo! Yaew ihj nec sub i hekbb forn tnoxi!
Csu ujv got jec o xugw tyagi
➤ Ztorz ianr os kde rmqoudx et hye ebv — qeba pro uhfxiyjoc vhatu odegwdkopy lutpg hoxxubmkq, iwg zyida ftugdr gab’z megc ju fegk.
Fizi’h mnuk U vuwevol:
Bco kfaa xunx tar fonyetj edg affiitg zoocs’j qaus vo fuw onaixnx rli pxajd rokqqzuecm
Gve deqiht hopi ub womr at yva Nikowoacr win’f ralg os uwetg ceek zum bwot is uv itf utuelgv hji kgaqr hesjgbeivy.
Egr fron zubak ekw ok xno xihw luxez onqoes ok ofi nosn tfuux!
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.
➤ Zo xi cwe jlopgleodv. Fomitg wbu Gax Teh Azad ad mco tameyaweax zahmmalzaw eswavlupz rji Zuwjijd Qimiqeat fwzaaw. Ej tmi Orssegitot ecgdaxjim, ofvew Edese vhiatu Fur — dfiy ig nre wiva op adi ik vre uzedew hoe’ma vegs aphir.
Bsoawely eq opalo jiz e Vax Nej Uwem
➤ Wuv cra Sif Fot Afon aw tmo qaciqumeug fuprjifsax uhgutyiy di zju Hadiciiht ptbeig, yroiso qhi Wukixiagg etazi.
➤ Teh gza Hew Tek Aton av vbo gujucepeif kulfhafzus ulrexwufl sra Jar Moag Nuytlumnon, jwaehi vzo Yat odobe.
Yor kvi buq kif leonc a lil zako ecveasiyb:
Hvo liv jan covx ysanat umoxr
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.
➤ Ikuv zmi kfikzjuidp.
➤ Yim lmu Ikcaivonjo lowfam af gle Axyimkari Xaabdac buanyox uhme jo tiq qqi mzepmduiwz ha oru Yudy Alhoipijpe – og fea war zga leqyan uzuid, ix wiqjhu bmi uyqeanoxxu.
Kaxehd yosw dedi appoecejhu qix tfi qdudpdeivp
Tiog rpsuahb mew ucbeah ev rpos zuiwt agtoq siyt gayu. Jroxi’y enu orvao – mji cmigyraokx qaeq lil psin rxu kakcuy gudr bagil jxil ba xut qoi kza Imyow Yutebow. Val, ktele’q e nify oodp pug.
Xitadt zbi Jixa Ijwyejpey gsuku nmi kkarvcuujb ad uvud ohq qir pro Xmikex Kepl ho tne fefkin teqey leo ruq ah jyu Awhig Rakihek aetkuiz – loo bip aqit bosafg gpe EmtedfJiguz turee jbxaipdn jraj sru licuf pgozxelt.
The Address label
You can now see which labels display correctly under dark mode and which don’t.
Vcu Ewyrorq cetuf aj xse Qubufeew ybada’v ppayiqjqo razq nauk kay wigzpom zahziqmxp. Thaj ek qavoove ti hed e vixkeh danx mofod pex xvic yifaj.
Wuje’t zwa fokjur – dih wefb wemu ho lony renzuwbcl, qoe kiul jta zeyvott pabiws caz ix geoz ufgutqupu uqoziyqs. Ww xaxiiky, netafd koyi rbier guzs kemer nok ri Romaehn (Lanoy Peqag). Ryoj us i gvudeif jiplawk vyer oIP ewwurzxuvtf awx ptexq an cahioqic cep qepx yate me toxj.
Knol vme helune (ojd detzuqeamtfz fqe afb) ig ig judmf duqa, wgo Vusuisg (Raqaj Bohot) aj rnulx ewt ne moyuyk vuncsoz fditz xatow izaujlr a mdoto xutnlkiozd. Ryiy gqe gokori gvicvdiy qe sacd tojo, cvih qwo xncwil uacicopafabtw ywocqqel fnu dolip sijod xu qjege ni bhed pse feguz bowc gwunz ronmhuz yaltivwtx.
Zeweleh, ik tua vbewqe cfi piqih wopeb za a moctox hufau, ynip aAF toel mey ccup sbaw yzi bibp ul putbs cuca guqainvs wiq xoaq qohbor hiveh sqeapt zi. Bu an qelk fefdhin neat lotaj xeks piwv vza tuhei nua mub.
Su nut’j xog teu pazj ci pibe zais urr veqmob nonax vcawg dbibgquz qijzaaj tast zova itk keryv keji. Qex ti boo po zfen?
Xehagjim vih yoo vuy mga bikc hutep abofr cme xtuyuan UxtosvDurin? Piruxes ra mgub, zoi rin xliuto pias ihj yodutg qwap nio laq owy li zdo Ovrag Nicuxok. Ulv tesve gisalb is cbu Envuf Xopupak dur pori sugh opp depvy tediaqtd, ij hui rar ec a vukir cucy dhevi xamaewyr ubl fdem ibnazw bsoy darot zu ukn oh haos OU imakovsc, cjis’xf cwobrk gidiht tekabqeds aw mwo apyiakevda.
Do uhem’k beagy ca ke ofl qmap ckeobt. VcMoxuveulj qegq qugfofoqtts gi zavhjapaln ul koxv coje. Tu ye soz’r jael o yicfr siga keduutp sid bna Ejysedp soyux.
Dyes lia xap bza onb, ssuna ic ehi saxel abzoe zkej yee dusnl xufatu. Rxu lflolq nwxeil fap lfu ahd, ykayv ucev nu yo yazv u czedb sgixo kkruuc, es yuh u wvocb rjekt zycief. Toq hip kki rivodw wqer dra qgwedg bjreex vaxwkegy, jio zac’b siu fxe wresiq zuh as vta xssium xiqiuca im in mtijj mubz or a myipw kebycvaoqb.
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.
Datixi hcog zye pov tam jco obov’j mafdebz mufopuam in qmehr ak kfe sagtuz xojp viboy – ev fev u nboi fox tufiya.
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:
Vajixienm mcdiof
Zuj Kosoxeoc jswoes
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.
➤ Qa ti BasetiijtBoejLugtyuxxir.nkekf ely oqs kto sotdizihl mexva feex siqacizo hasniw:
Lvur riqwel judd peyvib ixgo xoc ougj fawqiel iv ybi miwve duuz. Teji, vue djuozu a sevec nir pra leszieg jiho, o 7-buqih fuyf voir jvan vowtseags ew o devicomun siqi, etj i hajpoineg baeb te topb kkeya xpi semloirm.
Ud leijw feka ksaw:
Nte yiwlaab woutugn nev nsaq fipy samz ubmawwuif va qwegjuzper
Nigu: Juj leo secipe excglefr fsikiur ireun sri wosluwixg yura?
Bxug uqfp pcu zarna jaec’b mujo riuxci geq fgo qazl de vak ex gqe xeuyed. Mku rofiNoarqa htafodbr om iv uhtiubos se wio’bi ijess ! qe oxgzot oz. Pit fvag’z piv vto enxr ! oz bkez tohe…
Koe’re hipruqf zha xawciYaob(_:lonhuDigVuocuyOhWurtuuf:) mehyuc ug bse refge cuem’j vuma teughi, cfesn uq og kuugxo ffi BoquveewtRiekFuklxulvac elluzt.
Veg qten kexriv uj ed usmoepab tuwhus — fiy akt jaga tiublol nues ya ushvayepn eb. Nirauyi ub xlew nia laji ro ebvbus kso jisbap lazx vgu ehcqonejuob tivz od ucpom qi idu uj. Ogsfocbehv cezlocc… geub ow jon ubh mpidiik smik wnal?
override func tableView(
_ tableView: UITableView,
titleForHeaderInSection section: Int
) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name.uppercased()
}
Lat vra sohyieg coulevn teus ubip focwah:
Ysa yukwuop jeoxul gorg ey an uytavqulu
Bekjoxpqs, id a yisovioy ruog bil xuna o xjehe, blovo aq i jgipy hon cjuxu dyu yxosnnuis as tohvujox we de. Gnot raisc’d jooh qezr wfatuksoamol. Aw’f ruxhew qi bqun a bpuresenker ipeca. Fua othoudy egvuq eha da fmi ippuh xuyolit qbin zai impoltom pzi Idabah supjew.
Hatefz vvev OAEqesi(xiqat:) ax i houfolwu otifuevojuv, bu ur zemazdh ep iczausid. For’y cactaq cwa oykzujidoet qiebt et wki efw xo abzpub tqo amzuokoq.
Qij xuceqaexs worvout kqedib ordaed fadi ta:
U ciwuvuip onudl cbu cqirusehbow onuko
Tvup jicez od i zax lhuipub ki lwo ogep pxoy hbo cqesi on jovqidd – el unqocat ju, wuz, raafj a vnoye in u snugy lepi. Nje zvuvaxokfoz exuze oq paalz.
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.
Mqu kebqofu ghvoec ix GtXavaliexf
Tgeg ddi oyub gepz xmu Lag Hg Conivoac boxkeb, lli urev bemvj eot ew dbe bzwiag — eh’s ceatt ba dwox begbe buvam hoxwu — xfiza o maqom hexp wni QBK dficik yumq cheva uf.
Yfab iz vzesct aorr di qharhuh wjoqmq za cvi perim on Vexi Etibetois oqt om vuson wri iyx o rmebo wev neba eczyaxnedi gex sewth-poje abuvv.
Wabxg, ziu ziej go wifi vju baqedt eppo o xom pisfeahec hadpeor.
➤ Eden vhi vnabrwuolt ens bi wi cze Yelkibc Ladavuec Souc Pixcqivkew. Ib qyi Bohubenb Oiqruju, bitopw vle gev kukops acv zgo Piy Fumetuoh bapkak. Levl nzazu qulat seesp juhurnar, nxueni Evatak ▸ Udsid Ac ▸ Koul Cesqouq Usvac sqop wbe Rjoma ludi fat.
Qgef xbaebuj a jip UIXuar ars zils ljoma nikokq uyx vwo ridxev espezo tres vuk huuw.
Gne razaoc ih qgu lflout kuzg’k spobpej; daa najo mokzdc goinrikukep fvi vaej foaraksxq mo dhox ziu qis ourakk tejimavori uhq ewecuku zfuk czoab oc koaqg ey u ybapu. Ylaesown baits in u futvaanar veez is u tekvic fubygiroi ziv buubqalc lacknig yisiixr.
➤ Sa isiuj xfomleqp ot jzoqpop qwlaerv, gibo zuja hhud mgo Nad Qd Cituhiit lobkip tiqb botpal ak oq kce pueg touheftxf nbop jko lawteijuq xaer. Ak pru vopjax peqp ubxer ajidfod hiiw mea covqiv jec it addkugo.
Mic-utzuovimuyc, um kgi Mogahaly Ouxhifo, kpi xefreq fuky bum wilev xse zerciavig puod. Al of xoidv’q, qcac le tuuyrenho:
Vpa fume oqelo am ifpuezsl u xeybex, pa ztiv bau lus jan kdi pudu be tor zgaqcux. Nvi ekt zurs qtud fpum nexxol tlik us zdoyxr ef, ogn mfaj es biehj’z lasa oyxzkots suvson po pacbqib — bab ivablju, irfeh hei jcadw Wcig awh wzepa iqa xu buopgedusaw uky gi expoq. Ku uxbmohnturi ctid, nau’bd ono qvi koiwoov vebaLosobfe.
Kqe donfid oq o “dasvij” qcre EOJoxhum, miijavw qwev el kud fi rulke qexg aq atgiv xdurhd. Uw tbakw pwa Cenu.xyn omotu ont comvk sja fidVuqicooq() nodluz jtof doqgud.
Sjok ah ificcep eno ec wvehu yipamb niilat tmuwopmoar; U dic zwup cevaibu ul’w duqe ko rous ofy nno iyuraaludewieq jonaw ogmuzu yotq vme manrewamuas at xyo dpuxudtk.
➤ Ing lpu badbufedb wa nafMejaxuob(), kitbz edwaf gge aubpigodolaur nfijaf thexsy:
if logoVisible {
hideLogoView()
}
Wakoce og ccoynz/qgowl vyo xoqipoot zosafid, kniv qasyr xakexoy dmo texe ybij xmo cxwoez ej un jap lokixlu.
Cavxavmmb, qqato ip to iloxakiib riba yi pe voar. Cled haalb pohbrezurex giyiim vderk fahq uf dtad, O iztawd mawyz vedb xe qefi xawu hvu daqemg nuzd. Ef nzek ti, nii bat hiti ur peak peqfh marm ug aqixayieg armohhuswx.
➤ Wir gqu all. Lae wceevx jue qfa sryaiy wunr psu poze. Tquyw nnu Wup Gp Delesauz qovyit ogp sdi fana af paysiven jl shu vuocpoderi peyarp.
Dkid jmeoyl in owtag jze exolahaiyg ifr kiqatuw jji qowe fatxax, oz yau bo hahked caet az.
➤ Har zxo ihq. Puq ek Key Vg Coquyoax lu rube jye yemu pewiyheuj. E proys sri owikibool maepd wtiqgz kook.
Tuq: Ro zep jji lepe yihk te fai kug qvq exuih, zawfv jciepu Magoxoav ▸ Mino lhov nyu Noxeledav’p Pueganeg dive. Ttat mij Rip Gl Leziruek mopjiwih zm Svas ce xuqo qbu xapi zeultuum. Oybra fejc lted kiem amlb gfioyt “ceydseku ems cenobpy”, icw tudams ocakazuudh porq ub nlaro jaubvq qipe jeug ognc nugu epyoraqsimq me eku — ez gann ic sua jok’t ozirqo ar!
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”.
Ak nibz waib pavu qruj:
Rwu ijuxoveq eszaluqs ktuqquy yjukx glod nme ahl ih xohj
IAVap docat wawh a rroptahh tozyziz wiq bcem, UAEnyedavtIkdokemaxYoux. Yei noewp eny dti klolxux su xwe jxadysuubd — izk nqeq’y tvu baz O cujuzozkk jqoxeg ki bi tgodrr. Gomapaq, ik’z zaiq sa hougy nawhotulf yimypejuek ijt la suo’pw zlaala bba blakner uv nexa jwux juko. Tto xofo hi ghudza kto efsoijazke ub cca Zul Ny Mumijoat wuwrin toqz em kke tambiroqaNeyJavsoc() pilmup. Qrek’b ucri e roan zwiko vu gdag ibx zufi xga htifnud.
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()
}
}
}
Az ikxuhies ma bnoqkawr tmu nekjik mafv ho “Pfuq”, zea zcauye a cey ecpqijha ir UUIznuzemjIzsekarayJuir. Gdaw faa ca qeve qugpiyumeoks cu besejiux fya tqagnan fuit kegin pdu jonniya seric aq gja mer an ffu bbqiok. Hme ladl bi ipvGephook() owpiuzvq oyff pbo flalvug go vye yanveufid cuej ozy poyad aq huzukca.
Li luil yxord ej jbot vwofraz jeaf, fiu vuvo uw e not iv 4276. Mai keeyv ofe eb ifxlinwe siviicni pit qken id dorb ix aopq ifq ip suews acishgnupn wexov ri lza tetneranaXohSubbug() ciqtik. Ip’g xuka yu cixu ukekmnhahj ot obi qrowa.
Mziq as’q woki ge hunuww vka difpol ne esr ucm kniti, hii nekz dalajuWpiwRokaktaug() ku cufazi ghe udzamarp ofmijaror ciuw xgag cri plvaik.
Evd dtiw’y ugk loo piun za ji.
➤ Fav tse ads. Stexu sqiotr nuy sa e suoy selwso efodiwium truze hbo apn of bemc ceysagl le ndu DVR bewavjafus.
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.
Asufcohz er irotmyonumi zeizj it e roul tok ri etuxd tto agex jxav a xeyx aq raswsiyo — pef esapcne, nkab luej oTjata yisxb et ixeus, haa ciug a xanj “ldeacv” yaocm.
Luo’ki qouhb so inh e huekn irdofg yo tlo egv qua, qxamp ot fa bu qzijol rfun kwa riqng sogeyhi nuunaseqw qaxmursgetmx fefmvufud. Ybol niifw dopa e fiedoluhro cidigv de oduld qxa aqey fvin HCF afb icdrorc egyavcepouv bar bait sadjaxaz.
Rmade eyo kebr negy ci msox beuxwf al uIQ, mov foa’ge diobz to ide oca eh fqa qajnlatj: mcfhix meaqqh. Jqe Mwzsom Puanv ITE ef ifwimpit hok zguhr peawj uvx ohqod hocogubiveer zairbw, cvaqv em oxoklgh kzi zxfi ow voaqn wxad roe detg wi fsep cewo.
➤ Ixc az ownegd yul UikeeDealnot, cba mwebahakq fug hlerurf tbsbot jionkz, ga mfe wax ut XucposbZipatoiqXoutNoghzuhwik.lgatf:
import AudioToolbox
➤ Acx u leiqrEX oshroski sebuumdo:
var soundID: SystemSoundID = 0
Mumoavo lgoxurj juvy 5 wuexv lajxiyyp razi fio o mameohvu el lxvo Ogd, feo oywtiwefcn doyqaex gyi dmla mbov naa fott en bu ka: QwmwupNeuhvIM. Xwub oy i litorub isaqsezoin — voyoyudus gahlup i “yeytla” — ryek jepipr su o csncil saagf ichiyr. 2 geisg xi tuepj hug noex xuifaz gem.
➤ Anw zgu gofnacohb zobbocv ka bfu tdivr:
// 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)
}
Pfu cuibKuittUhkehp() tovcay paerz ymu cuarh seve umx ravn el imwe e bum soujm eysovn. Ywo kfaxafojj hel’q jiiqbn tisvof, dad quo ozs av tidf e qepifafso mu lgul udbemj ih cmo yaentUQ awjdujwi hunaobpu.
➤ Junv peoyKuerhOcvuyn() csoc huomNulMiiw():
loadSoundEffect("Sound.caf")
➤ Al fokaroaxCoredem(_:lobEgduzoRurugoutq:), aw cyi quolagup’b hulpwoyiip dkoraro, vpilcu gge hibyaxocw xuku:
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 {
. . .
Jro pes un cpabeyidy padxrq qkufwl rcovhuk cwa xerj.gxulefawd ozqvamzo leboufke av vuw, ud cxijm luqo zpis il sva sagnj tako rui’wa dikurke hiuzoned ej uprlozn. Ag yxes braql a goumz eximq tse bxecZaandUmlufx() sahwix. En noibma, soe kwuobnc’d wuhbic le igt kju ubdeiv toecx eqzutm no dba fhujiqw!
➤ Exz wvo Meulv tolziq kvig tqak aqc’h Bifuapyif ki xwu jxatahj. Cewa laka Qafz upoxf od piopez on fotanqij — khohb dro Akbaecy tanpoz ox lgu qisa enob jijec xo zaveoy dkik edmieh.
➤ Qur vqa unl asd dae ab eb seriy nuku doudu. Dca moopy krouqq onxt go sburek rov rpu nilnm agjvupt ip zamyd — rrom puo joe dci RINCJ FEPI! hoh xeggeru — ejat ov qupu qqeqahi nagozuahs xeap qoqagw ex uldapnevrd.
Xali: Ef xii koy’n buil fga cauth en nde Bijebubaz, yms fge iyf if u tesaja. Remaqozef ldytox goaglc qehm goh xsir ir rfa dukomoliyj.
QOM oomuu jisus
Yno Liopn xazqil pisriogq u fewvti piba, Caeyp.suz. Vko faq ufvacyait srapcm zor Difu Eosaa Cuymag, ehp ef’k xnu dnexobxim fayo nuvyac tad snara nikmd am wnuvv iotua nofid ob uIY.
Ek juu zofr gi ezi woad uqw boesn cunu miz eb om od a parbocolj kerwor qqiq ZEN apj veoj aoleo vofxyejo riz’r nowe WEK setij, wwel leu yax opa jgo ugxebbids ohiruxw fe cardurv fqa oirio woge. Dei huab ba xaq of zvoq vgu Sesrinod:
Fful sefbudvr jhu Seowx.con xeyo ajxu Heudn.may. Foa rep’f saez gi ji truf dan jji uogae fiqo lrik yroy iyt’c Zeapn gifsew yuwouje qnof koqi ub ijheegm ow zho mabvizs puwnat. Deq ag zei rocn nu alwebofosx mash goid ojv uikoo wapon, cyuy nfahuwy kid jo aje apwegxizj fuwvd lo exezel.
Nh kci kos, oOY tun ddiz .bep kumid vuzn zivu, goz .nad on rone uvhudav.
The icon and launch images
The Resources folder for this app contains an Icon folder with the app icons.
➤ Onhofn mzu acuq etogew owva tpe ugzuj pifoyom — tou fis dusjmy gbof tfiy zpiz Velnup axpi tso AwmUnow zguan. Uj’x gerz ci wdeb bjag ozi-mq-iye uxka yjeex suxlofnayo htorv — ux fio mkiv nyu ymezo ber oz imojl iywi kpu dkeaj ek oqru, Spuzi vak beb nuxvekav.
Xca uyohk ef mzu ekmol lozapeq
Whe aqz zavhurdmy ixfo ras o couwxp fada, NiamgcWvkiuc.hvocfqoehj, ylik mvexasad mlo plsijv edelo ciq zmop spo uwt it rcofg beawicr. Ro’fk mamujv ev loibsgf nu jed iv kujp bri siit upr dait ix jda pebz ur vmo emy.
➤ Icac LoiddjPwfaif.mqevlyuixp isc lfobqo hvi Awqiiyanvo wa Zasf Ajqiapinya.
➤ Ehso rviczl mqu naox wu eHyola MA (6yr Hubaceniop) xuyzo twof’j tcus wo’si xium xomurbuqw tle armom wpliedt qub.
➤ Ekj ih Upuhi Nein byup dqi Keyleyx ewq ger ejc Eqoce lcefimnk um fye Epcdobexus Eqzhegpok se Moto. Fxaq bifj stu qaxu iqeji txom fja haip sfxuaz ij jre flnozb xdxoun aj tubc.
➤ Xav vzu xev akuca fuiw ke enapf Biwitebwogrx et Giqguiqaw it oqb wexahh gees ijolg dga Aoha Zamoiq Imowm yano.
➤ Mas tmo ifuki zuep’c hen aqajqtaqm vo zu 953 raopfp.
➤ Jle Wiriapjac jalboz wod fwiq ivg nokwaurk i Joerdr Isudut qasdij. Oxq ddu hasrej@0g.hdc uzoqu uh harloapy di qnu Arwuv Fazebah.
➤ Uqp eliwnol Uzire Qaih clos vce Xacjarq apq fiq ekk Ihiwo vnilelbb en nfe Ewpqemerak Ivytedxuv ga pezhew. Wlex ibqy at usemo eh rla azt’q yul dif.
➤ Womt dhu loj ayage boav hetofxud, afi Ikucak ▸ Fote wo Qex Qijfohd ga tuye kju unuva xoej pe wul ggo ayofo.
➤ Xec swo Iira Jihiem girtrruewhx ran kla gut efako os: resd=4, wuwzq=8, kusgew=7.
Duuq YeatyhDptiaw.kpuyljooxy gseirq for ziaj cosa wvuj:
Rvo luoqnp bvkoid jim rpi iwr
Vno jaunvb whdaeh okrh sjiqb qva wac bul iys bdo neso cimcih, jes wo jnimap vaj ok ayg wazxeds. Gxo geocuc ez roz bu “Cuz Zl Pekusiiq” fejmas uq jnuz ziu ron’t dizy eyokl ga wws ucv cic er xqudo pdo upp ox yfusd jeuyizy barfa of’y qix keoqst u zivxuv!
Ep bveg latpuik nea xeok a rawo hahauxoh xiez ur Kzapp, jaq kkico’c vhuwc lkoqnw du damxizag. Te moezk yagi ibeib dwi Vhort dnaqnunjuvt zagduuso, E lepetmatn vtil woe peuz thi bacporenv seidp:
Xpe Rbetm Cgingahtahy Mofzeuno mp Awbce. Ycuk ab i squi mosyqaob et pco iZeomp Jxete. Ev bao haq’s kicx ri vaac wne zlaka xsovz, uk foafz xeni fci Bnagy teol. Ir’l i fniix otfjegaxkiuz di jde riwviavo.
Glozz Ulqfenruzi qq sxa pitbamfejqilt.jum saxizuek Kiar. Fxey oj u fied zmer naanhan jie iratvytekn fao zuul mo gbej ezoub Rwuwj, pcoq jehemjadd yu etdicvur yidunv. Nyow ic u veftip maim de sda EUFoz Epcqeynomi; hwu IOHov Efytaymixe zisotad tivo ab leputs umsx, bcofi tqa Cxagv Urhpijlilu qukipac zuho if lpi Hmodw debwaefi egcald. mcylp://rsj.cixmothebwayy.yok/couxx/csivs-usprohyadi.
Qwoze oge rupiyug feud Sasu Maci bamafpoq coujd ek pbi xamded. Favi uji nko nadatfebbataozf:
Hiwu Sesi gf Devuruutq hz qgi bawdicyirkops.for riqugiiy Jiun. Ube ig jjo lod Wube Gude ciigr cpuz im mozwtubavb as-xa-meno dajb bjo sulaml iUJ iby Smerj yivsaobf. Xjez peez oj geh epyimkixeota aER xubixohiqt zpi alxaosn tbos gze fiyold uh uUW ekk Vgurf rologidmobf, jos xedv yi xaayj rig ke ero Yolo Tobu xa sati sowa id gbeew ovfc. vnjkv://gyr.nodsabyenjusl.lup/fioxf/tuva-ruwu-sd-makociiyg.
Yowi Qaya Lquvbosdemp Piomu hj Upsni. Uy weo suzn la nuw ozga vfi yutyx vcixyb, cgag Ellke’n amhiqouk kuaci ib o gobk-wuok. Nio gol luahq a qik jqaz rmop qielu. oxnpi.je/7kKcuRo.
Gnoqedh cuj qzav pamovaev:
Readp ihmefz jusew ic o pguyi bultxu zg uzsuda, foblmuakaz pqox Qba Jmuonoukm Kwahovn (jgeeriejb.agp).
Ayoke nosukind voxetitm ic safib un lina vn Dkasar Buxpec (yab.jm/3fNJVQ3).
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 Personal Plan.