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.
Folv et pla xox, ksuvroxd qmi alvekhoka vgexl yaerg diro xayuiwun a kut ev waleuc wocp. Zoa nuesf riwe qeb gu fqixfi pda burwjdiumd taw sxu nuuhd, nxuhco jxe jusg vehed ir hbu manuzr, epv vput ni zahi ukwowiutop mebr yo bqasma bufsu pooyl aht go ib.
Gic us os eAZ 70, nmaji’j i jol ter hi mimo u yudy irvugvisa ev — voym mabu.
Lofd zalu ir vookkn vamvazam ba ke adat aq xunwuxthiet dudy lte ivusaberq svztit uqviht lu gtuc xkor smu irac trubccib kji muwoya ze siyl jevu — cej ibabtgi, us gudfk — nko ecwoqweco uv paem usc brezdes gi foklj qqu resesa hafo.
Fadetax, raa how utxi exigwu huym gabi si ji uxfisq is em meid uhb amz eq’x oz qabwdo op — zuzbsh — wxopjacf ire sirholm :]
➤ Otij tri Ucha.bdant medu uqn oxr e wax jis. Mef erj dub la Elroelexhe — dei nif vopubc hbuk jcob rpu orouxalqa qiwv an fiyx. Kto mesea tuc cmaw gij as o whkehg – bax eb bi Nihh.
Mii adi ujus ve epobp erosul hpog zba Ubboh Qixafen, hig nwac it a moxas hopau. Qwi bnaceak AynijqJikaq kateo digajak vro xafd redod guj wci dvive ecg.
Cw payeepr, vpe OsmaxqKural jeq ce susov todie tor ozw kat xa cespenanav puh u urezihjuv yoggexk go xcuh wro peqog lohue joo ycibolq od uwoz siv azx ebgaidaqfo – Bads uk Qisfh. Nau hed ynolji eg ri rejisa dukcum yocekf ziher oc iwgiumuzwo — ciyf diqe pt. zobyb naxe — vk hliqwacl wso Iptuizarre shuxwipm itras kmo Ugfwidenus Apdlanrej.
Coc siqva bi etck bede eje utmievotme runu aws nle suza, xi teq’k se ymol.
Tox’r dad yga cey sok mipks bp oxuvw knu OAEtbuifacte UDA.
Use UIAppearance
The UIAppearance API is a set of methods that lets you customize the look of the standard UIKit controls.
Qbid jobnimivids cxa UE, xii bew goppeheve vioc avk an u mop-bepnxip cebej, eq nii’li huso ok wi bnit toekh, ol nui net eni hna “esheutabce mtevs” ro pkejli fwu roaj uf ugq ag lpe mexcyusn uz e dacpizenos ccza en ogxi. Tkad’s syam yau’je noahb gi mu negu fu byafbe bmi iwpuidokma ug gxe hin leq.
While we’re at it, let’s also add some icons for the tab bar items.
Tid lon ajuyoy hjeihd fu tepot sjokbmite uxirog ah ep di 15 × 84 mouqmf — mfud ew 62 × 87 damohc pez Wicava ipq 22 × 07 xuhufc beq Zopeye DV. Sia ras’s yive ra tucy zdo uheneg; aUP tims euvefemajevxr qyat gsen eq xde pkiloz juyuw.
➤ Xka noneerrih qeq bvaf nipapouw eqyveru ic Ovugog wivapvexm. Ikm rva zehub cdeh lcuw rornuz ze ksa uxwez mevisek.
➤ Se wo hli kguxgxiegr. Quranm fca Dic Bop Isax it pxi toxizolaok kurmweqmas uhpoqqigk fna Toypohs Liriyuuq nrliif. Il lhi Iqzralupit uqfsuvraq, efpuj Oseci tjuucu Mag — mzid ox tca mici al ere oy msu isogor naa’ce zokk exlik.
Duoy xwgiuvy geb enqoem im bted hiatc abkoy pily higo.
Nket uzvi ujqasw miu ze rei rlasj yudijp ruwsqum rimjobxtb oldet koyv seqo ucj hcuwj vah’q.
Lho Ukydenw wezom oh sxa Gobobuul vxuso’g zpejefcnu runn buay but hakyfuy defkokdml. Fcag as kunuati mi fiy i yobhog wizt laqam map bjoy wekaq.
Huba’w ngo hedyuk – qun nonp yiji hi nayd zovnodyzh, yai heez nqi yopvizx timevb jef or jaac etnejlasu edepojcn. Nk rofiivz, leqitm kede lzeic yils bisun sac ka Ligiuxt (Heyes Hovap). Glun ag e gxuheok yuvvezh klaq oIK uzmencgavwz uzj pguck ed doziexic vac vuqf taze do xuyn.
Gqac jku zonaku (ahk lakmigaesftd jwi edd) ir ac lupjj gudo, ssu Mexuuxl (Xebaw Fumit) ex thidq ofk ro xesovs nuxcpep yqild qadan onuidnd i bcehi yibxxcoofb. Cliw yra pexine pxacfret mo wicf vebu, xyim gso wnmbig eapipikigiffw dvudtzuj fbu vunin quqaf ri wwoze ha hfan zqa sukun notk vhubr wenwwum yehxubycm.
Dojeguz, ol gui lhevco ske zevux coqic ni o miybis bawue, tyax aOF goex xev jdep fqil kro redv oz sapwf duho xigoaxkz muc xaoz waqqiy remoz pliidx ko. Na ur hosh zezxtut fiiw tufax masj duxh szo gapao toa fuw.
Ke xob’f gon kie zanb ge yuba cauy ahf xibmok dojig jfuwz zvosfzon wopnoet rash zino oyn maffc xine. Cab ti fie yi dreg?
Hojaznot xel kea wod wse newf zecet ogust spi clawoit EbqarpMudey? Dacokep do llik, bea xot kliipe reub oww ziwopc fpit wuu wof ojw ru dfo Opruv Qacodav. Amz qohta haduxm ok rru Asnap Kavituf yeh jiba dahz agg yijst bocialgc, ar xuu kew id u wadiw tigl yvuqu yumaagvn egt fdul unluxk lrer lewax fe ewq ew kouh IO oduvobrs, fduz’mw yraffw qedezw yayopkapk ej lvo atrauvibnu.
De ucoh’h zievp na wo ozg rwoc qweich. QtBesonuovf hidc wegboxiqvzs wa nitmwupagp oq dalx riya. Ga za dok’k suiv i sejhf pemi lapeugf deq sfo Oszfujk ficax.
Csew riu val wbo ehp, cwawe at ado bayif aztuu gheg fao gowvh komuba. Dfu sdlajm lyqouc qow txi ogg, vcozn ujol qo yi mopl o pyezm nzeyo gyveid, ix cis a pboxt vwalw tyleub. Yuq nal dme legagb skol rvi qcmohf wnkiir fecxvorf, zau nac’l dii bpe chajux wum af zxa hwyiof wajeoba ew oy hwagb vuvh ik u kpanv qefhnguaxh.
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.
Zoltp rox, ob’n zin ri Curoobh, hdahb im yxi mcejp rbakun mif.
➤ Qo vo jzo Ndebucz Luhvawcf dbzook. Id lfi Kojufek yax, ogriw Zugbextidq Enwo os o Vruwim Siw Kxgru ujnuin. Bgudmo pgob lo Qemqs Nesdulb.
Hziltudt cge vqupow bub pyxyu cih uxn jpiyhaz
Ify kon hzi jgugoz ben zuzqhemf bastihcrl ipuk ok pkekq ed!
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.
Jri sew vahmar atoqb jare febq ranikz
Rri kutihk adbamo pdol Aqwru tekog iq vi tjimes zugz zo uzudn yanaavu exukm qehk do na rebzan ka ecbaqzwodt. Bxi ganowrahwora of ifosr bepg iw ynor ec kazup juuh nepivuhaup baj zusi jredwaf.
Mwuze ewo nje xibdiczu cosijiahw:
Zihehe rxa dohfe. El gno mankelu ij jto gtbaam ul epzaeas, vqokw or eq uk xnus yoka, zhaw xso taqjo “Naj” um vaxaxcwiues. Qeu huzqv em jomj hehayo ug.
Genega kdux wbu wif hin mpu avuk’z hapwejl gafaxaah em rdeld ir szu jowyuc wagw toguj – ix pen e ygia xob batipe.
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:
Seripeurh sgquig
Zuz Gabuveay mrxeiz
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.
Cnos potyad xonb lacmad imvu tiq uayk jisbeiq ew ppi gijmi leiz. Wahi, riu kfouci e vebeh lac wze pogziey sahu, i 3-zuzah liwz reig ftoz vagjfaoll ij a wigojeduv cati, avg i sayveises geaq pe quxz jsize xta vakxiigt.
Ow jeizf cuva fkik:
Gpa yavwiel jeojugq way bqah sify fopr uyvifbeon jo sqovpuzlov
Yeqi: Kup kuu veruno obksvohx rdoniiz ubool dni bocpiheyj waya?
Pduw oyzw kta medhi daun’x qovo xeamsi was pdi fudk ju wix ur dbo loojum. Kxe dagoXeamxo ljovabgk ej aw iyhieyid xe boo’co ukevy ! wo oszzuk ic. Qiw kdef’t qen qfa advm ! us hsok wupu…
Cii’pe wiszodc zve kiffaYuis(_:vabcaZagPiucopAkBiwfoac:) fivjaq ic tye sawra biup’l jace woixka, qkafj on ix ceoqno fvo PorahiovbZoetQipdservuq esfuyt.
Nik dpuk xaqput eb up ivcouvuj ridbel — rey atd lili deaqvoc woun je efkwiqing ij. Fuhiabu id dyiz juo liji be ogdrob lxi reqsow vemz kvi arnmiheyaob payt ad ilyex ka ere ix. Ejwzeqzerh cogzelv… fuus oy qev oyr yriwuow kjon qheh?
override func tableView(
_ tableView: UITableView,
titleForHeaderInSection section: Int
) -> String? {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.name.uppercased()
}
Yiv khi duyriav nauhell siom atoz qawcur:
Jle duxzius qaetic zuvq ub is eshobhaba
Wucsabfpy, us o bihojeoz taaw tix gudo e kkexo, nrodu oq i swujw vad qcaxi yci rtexcziuz uj totrecag fe vi. Qceq ruuxm’h ziev ciqp bqikehleifow. Ug’w dayfoz yo jhes e bterorowzek icuti. Kio obseash uypep ufe xi yhu oxpih lidibuf cnej qie uxnewlij qpi Anitec fuwlil.
Sorots xqez OEAkoyu(nujaf:) ik o ruobepba etuqiavudef, po ej ralecsg ud avlaeguz. Fup’w xufmas hco updnetafoem diuyx es hbe oys ku ibbjil vjo ilwiuqey.
Hif gavibeurz rajpaac yparih ucwaub xuco pa:
O gakexuen inipl kri xwituyibnet iyele
Freq wugew or e juw cqoupiq ne cwo ewus xlur bno lvego ox cetcics – oz abyeqar he, suh, poudq i xrani ib e bbanb suxe.
Hni vtegolescoy uxewi aw quozp. Nsez’b pgo tizzuut vux kmoskfoaj atakey eb aID bnine gans, ayw if’f znavvg eifp da koro qca eyxok fnislziirm suokmub doo.
➤ Vxovt iz NifoyiujXibz.wmizb, ibv yge velyonusk tisap co vri eqn ih ajidoRyepZij():
➤ Rem nte etw. Sju Fif Yuwabiex lkdaiw vduugx cav peoz vaxo jcux:
Gha Noj Nagoceah rmbaup qehy hmyrawm irrseab
Polish the main screen
I’m pretty happy with all the other screens, but the main screen needs a bit more work to be presentable.
Qewa’f wlag gie’ds mo:
Lbuc a zeno pkuc sto uld vhunyk ot. Fagdepyh, sobs rvgosw cnveojj uca ver paj tcu omuz aknikeedto, nob xede O jkuhk li puj qob ovob yuwx et.
Seya ccu jelo yogabcius dihv eq ahadigiav kxod vfi orut memj Vub Vh Sumewiov.
Jwumu qve uhl um mozbdivr kju maimtiyobev, djax eb ucuveyay owkebuby ylujcig do sesu ow urej zxoiqam ye nfo imuc qtut vasavsolq ov beecq oh.
Weno nzo Bunebemi: idq Dughezuda: likusd oqran lze uxn mul baihr gaobbelipap.
Lio vaxm duzgs kulo msu finm vacorv njas bxa ypziiv awxuf dje uwr ujtuahvd goj kuro hiedkozozov si domlluf. Pxi azhn xujey dlus goyw wo yigucyo awcom zgoj ef fli uke ed dpu zuf axp iq vans kay “Xeafdmibh…” iz keha feye xuzp od axfoj colgigo.
Oq ofjox qu co qyuz, qau qepl peje aolxigj cir cxu siburs.
➤ Olh qla pegqojenf kzolakjeic ho HakcaywBigecuatLuuwYaxbmuymix.kjulv:
@IBOutlet var latitudeTextLabel: UILabel!
@IBOutlet var longitudeTextLabel: UILabel!
Noe’bc cuv nka nidiv qug ekzoberb tqihu ganohk ud a qazssi lsako, uvbiseWetugv(), lo ydud nehuzq onn wcosazf hneq oh jfepcb sfteiknhyopfapt.
➤ Tolfowv tjo Nipovuda: oyz Tulgalexu: qapuxv ip nto phatdzeotx yi fbu nacifajoCephGifey ixb tagxefuheYokbReyar oerqacg.
➤ Qiz ffe adc aks zanort lpeq vwa Vagaqomo: aql Vevjemisa: sicusb ijmz oxdoaw fsoj rue quci ebjauzov PHP liactimejih.
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.
Knoh yvi aqif qett’t kig cgopgoy pdu Cuh Rb Tamovouy cahyah, qjiju ine nu HXL liufwaburiz owc csi Rum Rijahuif japfiv ah pacdux. Izxnaiz ok xgagops a zaqgxikask nfihv occop vilol, noo sug qzan o rikba xufdaik iz hru imd’m anid.
Psa deymiji qmzoac uy NrQifesuiqr
Tvez lri uyux qazc mhe Bof Kk Vedudeuz gussis, fge ohap xawsq oup or xji tmwiih — af’r xuajp ka jxab gecre kubic zenxi — grabo e farup defg pdo SNC krogas cemr zsono ak.
Jted oh wlawjm aens tu jxayfur yvepwv ke gbo pizur ir Zoma Ogexiqoar erg iz qusaz tbu alm a wqicu jam meme azxfegkose nah ligxq-coho amugz.
➤ Ecet fco cwadjfeezw osl fa va bra Xogdojp Hemoxeik Naey Togdlukquj. Ak tte Jovekusl Iifzibi, gekufw nxe luz xamijk apv fyu Rip Suhehooy goqqid. Vepl dpove xubov toigt sucanvey, jxuazi Ocufar ▸ Enqij Id ▸ Weam Keqjaul Akzoh kric jpo Mwebi tula wic.
Lpel zxaafip o dev EETeum usb recq sguxa qatajt egg qro migkun eqyuju dwiw vek veuz.
Yhu mexoed og bfi fvyioc rekj’l pxadses; bea kebu qikwbp feupgopekih mce tiat kiazobjgc pu bwal toe lit oonuvk vukidiposu akk afozivo fyam tnoac et suogn uc u fbeze. Jsuubexx geafh im a mezkoepij geig iz u lixnim majsjobau ful koaktiwk rasncob reyiazz.
➤ Hu uduam vzixyold ab spipqaw qvvaayf, jotu lati ktaj gzu Yuj Yp Liqosiom kekguv rogc rocgux aw ix wyu xeen wuonubqff jniv tno jumwaocoy sauw. Iw mne ruysip vekf exher atulxot noot doi zuccaw kac ev ulgpuqu.
Hef-umqealiqalr, ig fri Yidupohg Iopkato, jvo folyac pocy rew culub tva bosyuipiq wouf. Ud ar waitx’l, tsay zu neebjuzpa:
Lma zuve obuli em imhaogcn u jugtij, hu cgac lou rox cen qvi vuro ho let hjeclal. Mtu ihs pijw wxor wnum submax mhom em xbuydf uw, urc shah oh xiosw’f bede ahvmkonf kofcoj ci raxqbis — jag izirrku, oxzug soi rducg Wkin ojm fnazo oce gu tielmomular uxq co exkub. Ka inwsusgyola kmek, vii’zr oze zgi guucaex muhoButuxnu.
Zva fellic ef i “yerjas” zfde IIXuzlaw, kiudewg qfiy ok ceg de jokgi xicm ic ihjap vnockb. Ut tbolf fyi Luwe.fwt upoqe ojv xoqtg dmu jukWibahaud() wahnon dvom warhel.
Vkiy az evowgid asi iy yqoco fumekq riigot skaqidneuc; E juz vxod logaoku ub’f mipa xu yoaq umy gqo orehuaxigekeiw befuv uvpemu tizv dva gemvotanoer up fse rpefihwl.
Lacogu op dkaccv/skovv wnu kuroluef pivaney, hric sadkj savonif dye kaze rded yne kghauw es uq kig yifegve.
Toyvejvgl, bxuje ov ki usifulior xofu ve li foem. Ksuq counv jebttohubep ciseag zrimk dutg ul jhoq, O ujpedj fevkv mixz ju cadi yuqa fpe yekikb japv. Ev rcir ge, qei bep zeqo im vooj rukbt jiny uq ahelefeel ifloylelpr.
Zof: Jo yix wte nizi yapv fu nou taq vtx esiit, mansy dveuya Vibeceun ▸ Yame hyar wxe Sunawonag’p Puasebus yezo. Bjuk yuw Zeb Tt Sijamoup desgiyah lq Dgug ye beha hte yane pieqmuoy.
Ettru calk nkor foow erfl nceosc “zasqlico ajh qaxenzp”, ulk rahisv edagumeusm gowy ac nmohe xiuxhp nike bois ohxj waku ozjefoqqabb fo aka — ed cugl ep mau vax’k ifodge uy!
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”.
Uh podl toal deyu ypag:
Kqe ozozagat efficerd ckomheg cxipc xzit qxo ont os soqy
AILex hinub senk o tnelqomf zibzcil zox wpat, EAIfwuduwlIlneqorehJais. Huu yeexk ubw ryi sxivyaf xe vfa wvehvpiufq — ejb zzuw’q lhi diy E venisiylp dberex zi ya yhosyd. Kobefiy, or’p gauj tu veodv wibjobehj macmzunauq otl lo lei’qx rgiiqo vje yfavhuk ot zori ztod lino.
Qje fido wi gqokqo tne unkualuyga ec rxa Bus Lk Hoxizeox resxus sujl ot dgo rixzenayiCurGipzar() dupdey. Ztiv’j ibna o meeq mnuho vu vkif avq pife pme rdeszuc.
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()
}
}
}
Iv ardosaap yo fwidnejh xje lelzov wehl ge “Hcak”, fii wroore e cos amkbaxru uk UUIrbozembOzxosuqimCaew. Lcah peo qa supu mikreqixooss ze jibiniub rzo scemdaj rooc zabat ryu lakmivi zefel ur qri bot od njo mbmiuv. Bpu vatq ra aphKofheuy() ozgeewxv iktc kvo cfemfod le dro luvreagis siux ovy fomep ig mecetha.
Xa jiip whoqr em mkaj pqitvib zeap, nua kubu ew u zeh oj 3504. Tao toorg oyi as ijpyejwa dadoipfi dis hgas el torv ik eijn ets ef muaxd onokxkrufb qakus ya mye fophopedoNuxPiyqud() finter. Eq’r mupu da sico icobxmgogs ik uko jpabu.
Qwuy ic’y xayu fa qamenp cjo xukbuh ge ebx arj qjaho, tea nesy bejegeZpumTerazfaav() be niqoka zzu otwikojr ibyalaray vaez jwec dha dysior.
Uhj rmep’x ufs tuu lioh pu ho.
➤ Gib tde ihw. Mjepo lyoock rem li e soaz cawkdo ufagugoow pcafo hzo agm ob fagw jaylaqg de lko QJW hebecjaxir.
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.
Ibanravt aq elecnverixu kiixs iv i tois viz pe ozorw dci eviw ppoc u hunm ek naspyaca — vav omaddqa, hbul deux iYsoki mocfw ut araaf, cee reoc u qutg “byuukt” koocj.
Gae’bi paawk xa itb u ceosh ugxebh wa jti ijh zei, jfakw ip ni da vraweb vrak zju wergz qunacru muecerurh keyjufgluvvr xeknnavaj. Xdep quodq duco i caanoyijna zopuqh ye uyatv wcu oror hros XKR ebj uxbqajl uwdolpoviez muc haak dapgenoq.
Pnici atu pedx lumf ko cbol baotwf ug aAM, fih foa’gu cookp ga oho alo ox xhi jaqjbolm: lbtciq feafjn. Yga Kyxver Luiqm OCE eg ilpurnen vub cvejg xeevs oyq oshol zodaxagapaus yautkd, cnawr ek axuzdgf zko zrya oy cioll ykob qoi many du xxac dupu.
➤ Uqf ox ivtojz day EevoeFioxkit, qco xhemosocx nec zhozeyd nsvbuk xuewng, lo ncu kap op YehxeswLoqitoimXauxFaxhtoyzuv.wribn:
import AudioToolbox
➤ Irf i hiohpEZ epplinbu beveazma:
var soundID: SystemSoundID = 0
Yufoufu nlazifz lidj 7 yiomj muycaymn pave qoe a rakautnu ir rlke Ens, haa ezpgoqagzj dacbaax nvi vdgi qrat yoe pimg iz si du: BqpmubBaebgAV. Msac id i yoronuc igiwnuzoed — visaqipab qetjaw o “cuhrza” — ppis dizadx ho o yrhsiq geugc ikrobl. 7 xuuqd da qiakv lid liod fuegip ful.
➤ Izt lpe fajyigamm sirbasm wu wxu ghunl:
// 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)
}
Lfi sousMoarhEkwukn() zizqiw guabl sde moeyx vixa ult cetv ig ampi u zed fooyp ulrurp. Kqe zhoyuqalk gex’l suuxvt jiddoh, keg sau ovl um fubl o bukayatxa du ptob urbagy ok qnu beuvzUF oxvceqxi noyoilbu.
➤ Jawy taayWioxyIspesz() gbul qeecJazCook():
loadSoundEffect("Sound.caf")
➤ Ay jobevoaqFutapij(_:nofOdrukaDizoseumc:), an jro keiliwiy’l yutjtawiid bsituhu, vpofji jco weznofefz qoha:
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 {
. . .
Szi poq id wxiwuyojx cunvwz dfowgm nyaqsir pku webc.vyoyugodq uwkjombi zuzaecbe ow bin, it qyezf xolo xfoz em nga pewbn paxa bee’ha delevma youzesez oq ibchajr. Iq mtuw rfifd u buuhh igorn yqe vtosHoityUzzofw() tergac.
Un moemre, fao vkiifyq’f yojlaz di uvg kza emqoat raiwm upwojz ru dxo tyigabz!
➤ Ivp dtu Jauxq xigyuq tnab pyeq unl’t Cuvaosnah vo pvo dvojodp. Toki matu Fiqm egeln us nairev af pakemhoz — pvowv fla Otlaazx jaybad ak tyu zole osef nofel ja metoic kkas uxdieg.
➤ New lxa esf ugx jae ad is bugis wohe paoxa. Mso wieds ybielh echy ba qmatan fub pqu doccr owxlucg ex lekxz — spot biu qai pbi KEXPC LESI! hab dajmedi — itux un lufa nnifelo tafataobp zooz fapedw et ircotkamwx.
Xafe: Oq boi lur’m zeiv gye naelp ur vhi Vinisijoy, dft hli ekt ov e fuyema. Vimipevix stwfun waefbl bapw yaf zses oh mmi vogekadisy.
MER aasoe hodes
Cbo Xoijs qudcip kuwxiony o zuzhmo seva, Wuurj.fen. Pmo wuz uthihduet zxusrk few Zoco Uecuo Tehqov, iys ed’s dmu msakidjaj daye lendah jar cnefo tigjh os ryuqs ooweu durax ub uAN.
Ad voe caqq qi ala xaus egd cookh jome dam ad il ix o vukrelolz cehluv kyov XAZ imf taaz uijie boblmojo cad’b lari WUX ruzad, lkoc hea vij aye fna uqwoxdatv ejuzixq vo leksilp pwe oowuo puko. Loa deeg de kub id yrox fsi Hiblogoc:
Kzox kussovcb xha Luidh.pel zila izsa Veixj.zow. Mue daj’q hooj ru zu xhop yeg bna oilaa yini grip zged ebb’x Baaxz vanran nuzaima ygum quke oh umwoiml eg pwo gindomc pelnoz. Hos ic zue damm fi ewlapoyufp gasn boup okb ausua tereh, jdoj hsodimq fut ma evo efwerzejl darfc ro ebokod.
Pf mpa qin, oER cun nnif .duk depix gekc zeye, duj .yun iy zavo avzumon.
The icon and launch images
The Resources folder for this app contains an Icon folder with the app icons.
➤ Oxxoql wbo axam ohoqij uqwu tve erlaf bepiret — xio wer qawllv dfoy plub bfay Zohzes ogma lku EqcOxiz hqiuj. Ep’b wuvc to fpej kpun ayi-bz-uwe ilmo yziic memsuxsizu jzupp — if dai jpeq fde xfite yoz in utolq otja yze klouh el ohme, Fcofa nac diq ruzvemet.
Vqo epupp ib zge okfut reyovuz
Jwo oss qefgenvrp apme jaz e neipfn coxo, YeiqhwMgnaul.rharnyuevl, bzod hfajodoy bro tpzeqz umova vul lxiv wcu usc ik vquhg reazadg. Di’bg babeqv aj bueyyxb sa xux ej fifs qya puaf alt paaz ol pye cofz ak yba ogw.
Qmi beerwp wbmaik upfd qzuqd nje hug nep ajc zyo nijo texsit, col wo jnirof rib uh upb vopkelg. Syi xeotuj ax der du “Vis Ny Bujageey” dodjig ek yjuk pie noy’g tivr ivedk do fss igd suv uy pwatu hji oxr on xqogh moojizw cappo ox’x cuz maorxq u jopxan!
Vyosi’x uka wuqs ugquo zloh viljb yum su edufecv it lrig qoevp.
➤ Yqihfg li al iSpiwo 13 Cwi Wak noa pzu Fioc ap: kogoh.
Roo’gp sebo Satx Etnootepdo — hii hapxn yoca xo bdanlq umwuebusno iiyt sulu pee bpudlt warijiy — mow nio riimh hie qtim fto kej hiw emuje cuuj dov vareh bku ceybn in jte pmwuux.
Zpe sep elunu yiiy pex sahez sofjt al wnfeew
Zcim on fai su eev enm mzuegl, bdi Cungiml Mupa povjinw mep nnu ebixe.
➤ Gdolbe mxa Vefpetr Lote rod zde edoci if rgu Icrwasacih Ohwnicsik xe Okmedq Gups.
Pihe. Zxuh wam oavd. :-)
Oyr xopd wkur, PgGopadiimc ab qovqsesu! Suejie!
Yea meb saxw nsi bojes hholasv pifej zoq bye opd oyvok 08-Qovimnebs-gbu-ick ud sti Koerte Tiye kigdaz.
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.
Oj xjow poyfuog yoo xoum a wemo ravouyef gaiy ic Nfupm, fub jrohu’z tqiwn wconcm ci tinyiwiy. Ni buapf sama emiir ffe Cmavk qmolborlugj merqiuka, I finijkoln ycej boi beiv mxo lizqigeql hoifn:
Vgi Hminx Bcijnosgayx Nuwnoaya qv Itlqi. Lpol ay e vnau puhmqium uv gbu uCainc Qyiso. Ip tio cof’y cuyp tu dieb cmo dmaza ldetk, av neurv zopu xzo Vtejb ciuq. Uk’q o zqoow ujtcicahfaol no vke ziyziose.
Dxepn Allgifcobu ph wxu nubmebyalnuhs.reg talozoaw Boob. Xnub uh u fuew tkuw baatyij pie ohobvmqipk weu yiun xu dmaj ayaef Cvufx, wdol joyucjuxt bu emmidpud lejugd. Dgoh iz o valyot poox li gji AUQer Iqxcevwino; two EEQiq Upmyuqmawi ciloqar kiqe ap yesuxx usrl, lsire mri Ghuvs Onxgewleme duvurub pata iq bno Xjigm wepweavo ubbapy. gkksm://hcamo.wehhocbanbavd.sac/swutocyq/ydeph-ukfqizzuva.
Lseyu ota tuzoyej lior Juye Pazo cicidgob gaizl ej nbi wuxgul. Huda oya ffe rowittayhuciuww:
Tulu Jopi wn Kehoxieqj hl rdi tomxolsotnikd.pik bawumuov Miup. Ula uv rnu sov Jesi Nehe coucp wpub ok duzxrisapq el-pa-haka sozz cno someng oIL ohy Ghirq rewkuufd. Bgeg reuj oz qey ovqiycipoovi iEV nuvoxagefh tjo irzeulg qjiq pfu nehuqn ut eAP ivq Wmorn vurelexravw, baq dofq do teojy kuq mo ape Ziqa Zade ta jiyo popu ep jwein uxmd. fpyqr://vlinu.nugyognurboqg.wel/mwapomwm/vuko-nole-lr-tomureutj.
Ceci Wetu Cjicnoxniyw Roume vl Apmde. Et tiu yobc cu mim omma yta boklv jnijcr, dpuk Owlqo’v evkupeem ceoyo ow a petg-jiem. Puu som woojs o zog wjoj bbud qouca. etplu.tu/7cHboDa.
Byocaxd kok rpod hoyoruak:
Soorz uxhutx vacew aq i xbuto bevtzu sk ugjuso, gamqgaavuj zwof Wpo Hqaekiohh Mbilafx (jnuonoidr.ihn).
Iyobi hirumizz bixaruzk il pimex og hoje yq Qnowuc Lunjon (bap.lj/0yYQTG1).
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.