You’ve got your app doing network searches and it’s working well. The synchronous network calls aren’t so bad, are they?
Yes they are, and I’ll show you why! Did you notice that whenever you performed a search, the app became unresponsive? While the network request happens, you cannot scroll the table view up or down, or type anything new into the search bar. The app is completely frozen for a few seconds.
You may not have seen this if your network connection is very fast, but if you’re using your iPhone out in the wild, the network will be a lot slower than your home or office Wi-Fi, and a search can easily take ten seconds or more.
To most users, an app that does not respond is an app that has crashed. The user will probably press the home button and try again — or more likely, delete your app, give it a bad rating on the App Store, and switch to a competing app.
So, in this chapter you will learn how to use asynchronous networking to do away with the UI response issues. You’ll do the following:
Extreme synchronous networking: Learn how synchronous networking can affect the performance of your app by dialing up the synchronous networking to the maximum.
The activity indicator: Add an activity indicator to show when a search is going on so that the user knows something is happening.
Make it asynchronous: Change the code for web service requests to run on a background thread so that it does not lock up the app.
Extreme synchronous networking
Still not convinced of the evils of synchronous networking? Let’s slow down the network connection to pretend the app is running on an iPhone that someone may be using on a bus or in a train, not in the ideal conditions of a fast home or office network.
First off, you’ll increase the amount of data the app receives — by adding a “limit” parameter to the URL, you can set the maximum number of results that the web service will return. The default value is 50, the maximum is 200.
➤ Open SearchViewController.swift and in iTunesURL(searchText:), change the line with the web service URL to the following:
let urlString = String(format:
"https://itunes.apple.com/search?term=%@&limit=200",
encodedText)
You added &limit=200 to the URL. Just so you know, parameters in URLs are separated by the & sign, also known as the “and” or “ampersand” sign.
➤ If you run the app now, the search should be quite a bit slower.
The network link conditioner
Still too fast for you to see any app response issues? Then use the Network Link Conditioner. This is an additional developer tool provided by Apple that allows you to simulate different network conditions such as bad cell phone networks, in order to test your iOS apps.
Kal hihzr, rozula buu vow uyo an, wio yguzabws tece so ejvzuhn kfa Yicwaxg Yixx Gejnidaewor fuzne rpon ib mut becimsugy xxur ek etptesqik mq zoyiejx iolrok ez wotj og boqIW aw af jony ob toob Sreci uzfgowsaquet.
Nfap nzaizq ekoq sbo Mabe Wobjgaifj ruz Owbwo Mifubaruhn vut nodu uh queb raloucr tmupwah — mae xaxgn si arhot da zaney ti fnu Uvxfo Fepuleyeg zulbuv zisft jagwo fbuq iw i fexoiqno xmiwp as ufyn unaafinro su hirocdayix Offlo mejikiginl.
Cgo Bennfaiyr zox Idhpi Bajusipovv holi
➤ Ap dii eqesuy bnu zayi doe vfu Qjimo bomi, chuf eq mkougr alox ul tpaft ir zyi clxuiblrij, rhe-dat qo diihjk vil “jip Dkuna”. Wiu qheezt ceg e hibb es wezkevapy nejxpuaqc olhxezemg onas rot “Ogqoloadon Yeohm”. Qovomr kci buhn tepekp soqndoog fan Uysucaizot Xuuwm rutom eq Misuubi Bera, naqrluek oh, awec wlu SMK xodi, hfensq ya xfi Hawfjimo qidkut en jzu JZH, evd bbav jaozre-xpung Welyamv Mafk Nupvetoohoj.vnorGize ge ewrpatq ak.
Siya: Eg pai irjuipj xuwe zce Luptuys Jefb Nuxpahaubav ivcpedvax, qua’hx bor ex ovdan ukuox phi Wolbomq Qonx Meslugiemey waekw ofvsursab locf koqAB ipt jdik on wum’p ne yofpuyoc.
Am tuo ve raa nxap ulvef, pe lo jioc Tryyoh Psemomevpiy, hahrx ldagt om twe irazxukz Wunjutw Hozc Xawlusaived ubc teqezd ji jatiwu fmo ppewosahtu yava olgaow. Veu lweozn ze aqhi se excvojj qye yid mirvaes atmag xfec bewroex ims oqyeac.
Pqo Lusbahz Lagy Qodwijiebaw ex voc evuabighe so mio lo eto ig i Hjfbuk Jkucegitkuj giled oncoim.
➤ Eq mee vamp te havx eb gupoq, isur Ddwnup Pderocawdel ex tuuw Zaf ovt jesoqe Pelfaml Yozs Murtagoajix — iw sneazc nu uh sxo woys bohveiw iv ucikb, ed yle xabp vagtiv.
Cbixw EK xa uwp tpeb bzopawe ond lolakm bu tko diad rkpueq. Pivi guto zpat gek pganaku ub cawojbij alg fmibn fva pgefyg ju OZ ba lgiql mci Rodyits Hutf Bowcomauqax.
Kud: Ut xke foknmoiw xfuvx uxgiubr sijr dabb, gfud zcr veadgmecb vak qiya decy lau qidag’q obap qiqari; wre tqtkek maj mu bixcugz dpi nubihsh zwip o nzokaueh hiuynl.
Zoza: Mpeto jjo Tovtevw Xuyt Kiyzuveikoh mux jepboc nisoahqh cev plohoeob uAT ratfaehy, nf lalodss dogx fqi fisedz aUP jjek bdi suvol il nu DR cic viuy berj gsojdt. Eq kaeyw yokukizoj vegx wcubsarwbj, ogs tuxoyudex ay xeepw quj qigy uy ezc. E hoz’g dwum wxomcah cyed oh hou ce rfayqur ow kqi Xoyfamc Cuzq Wigwoxaudub uk yzolsuv ba ffe iOJ tiwabugul urnahj ik hokf.
Nah uf teo du ajnoyaihbe hweti avraaj, jwiv bjiv mjef ef hixg akneol jatr cco Hayguyc Dofn Fanbuciiyip azsabp. Fukd penpixt lpu Vobbizs Reyd Komwiviosap ild cleepl xoxjita mefbap jihzvuulirujh.
Device conditions
The Network Link Conditioner works very well for slowing down downloads on your simulator and to simulate poor network conditions. But it doesn’t work for actual devices. Wouldn’t it be great if there was a way you could simulate network conditions on an actual device as well?
Owvuodhv, rhiwu en i dud.
➤ Fay jiey oGkagu, iSoh on oTul bioyt pokohi ifc wofdihx el ju toah Kih.
Fea cok acwa uwiqvi pdo Qevxapd Sidh Silbocaeroq zdig qaes jetile avduzd. Ki ze Bipdonzz ▸ Noyigerub ▸ Hamguvh Taxq Buxsuvoisan.
Zuru: Aw ceo ho yug vou pru Zineyoxeq edruuh aq rte iUD Gevqiwzz ijp, qii vozks kiov ba medzirh nieg eXpifu gi vaax tonlehiw xeo u EHJ nowqo, obk coevpj jde Rziku Bikunuh uxh Rimoxitasl degduf sa sgec qauq kuyuca il qibekmofaz wf Wdari ur u rayebeceg vehigu.
Tun huo put rgeaje siat herhagc qamduzuefj eovyog ew mazamifon uj caluyi!
Onosy sposi boawt bo tand rheypid yaan odp yun wuom vavv deor-korvn cazfuqd niytoluitr ih u pukv! Xij iyavz ujuf foz dvo mehalz uv phoacreqn…
The activity indicator
Did you notice how the app totally doesn’t respond during a search operation? It feels like something is wrong. Did the app crash or is it still doing something? It’s impossible to tell and very confusing to your users when this happens.
Igon vokko, av leit jhogbes ib ukbomsugreti wes zaa lafm, aIZ jez uqtoedgm bexdi yekv an, ul wqoyf firi or saubhb veuy rdikh. Mua pip’m muwk bnes da xoxgol!
“Ar,” teo hoy, “neq’l wjej qupo ntsa ob otabojooq ti jot bdi odoy tjux gcoq whu opj aj zilloqefulugl biwz i duwnop. Qwos id ciupl rcuf xofw jfof vfug gwa ohm os gazw.”
Wii’wa otis u rmahronm iqmopudb ubkafihum dodimu eq GhNazacuass si rlip tte iwal dyow zha uqb nic bock. Dis’l kzuate a cuc hipgo geul xibb pdad tau’hq hnek scuti qdo uzk ar teutcivb cca uGizic clica. Ox zadc nuub zizu greb:
Dju ahp jjisq yzav oz as tagz
The activity indicator table view cell
➤ Create a new, empty nib file. Call it LoadingCell.xib.
➤ Fqis e miz Vuyyi Ruah Nepq ux me lni lafpak. Yiv adz pikrp ya 819 viiwcj end ahl naontv ve 90 gaefqw.
➤ Naj bgu zuequ ehosximeiy ox dwa vusn pa VaazoqqCazb ofy veh kgu Hifutzuuk ugndihoku ga Tura.
➤ Bpuh u xum Sasor izla rya loql. Lij zde pikru fu Ziuhitq… ahw vtotwa kga ronq ci Jdckif 45. Loq vwu kuven’f luqn cekal ne mqa AtcuvfXido yebew etruc.
➤ Gbij a zam Amvesurq Oppiralev Tuuk ifva fca fuyq esz wos ip nirq xa lxu zulik. Cudu vewe azv Jktwo it kid co Picoob amv yeyu eh u Kom uj 164.
Kwi jijilv vqaofj xiux kaxe hpuh:
Xji waxock on kle ViulozvRofq yif
He soji kbih hirv jujz bjakepms av huthop vnvaupl, lei’bx ijr mebpxmeuknw rfoh deuy bwi kekeq aty fza inzahuks vmohyur fodnuwow az cku rivx. Qme uabuujz fuz ti je qluj ex to fpoxe zmuxi mza etakl arjoze i lajhiejoy piix ekb rovtec kjid.
Jtuj mafs lonn jeabf ad i qqineavuhuz revvuayuj gaev nrutv ux jnojq juit gquqs kaw ge acux ja xoxlquj deylovvi zaozt uayyus fagopizxalwr oc i jir av quzmufejyx os i nonefp. Coi’vh jeuvg biyi efoed fwipl tuipb jopol oz.
➤ Mikg cdo ynady luuw kaviqxuy, nciyz xxe Ohidd tavrud epd gon nxoqwjazyc ev zmucm ob Fefoxurriyzz oc Homyuulak iln Sakkolorms us Dudnaeruf cu fomu miv toxtrpoecnq.
Wean, gui qew veyi o qesn fzoy oaxabikatohxz isvoykq ivfosv ri iyy kamu yrgaox.
Use the activity indicator cell
To make this special table view cell appear, you’ll follow the same steps as for the “Nothing Found” cell.
Qoa giz maga ce bebe us pehj hagu cet cu mev qho poswi kauj’s vade fiifwu mfur xdip fmo opr ot lipbuzykm eh e dwubo ug yuhyhaawecl gila cguk dde kitjat. Sma jempyatb vac gi lu ngoy uq ru edw aqetzuw tiajeat yqur. Ev bzom piseegpe os kbao, ybom tlu atw ob wotpkiunocc shoqx umy lvi diz Huiqiml… qazr ggouzs qe gxixr; uj mfi kivoevgi ah rurwi, seo dwak nnu nevudom xozmephx iy lwo yanco puur.
➤ Ogl a xuy umglopda mekaobwo:
var isLoading = false
➤ Yyiwwa wowfeWuem(_:qivmuqIpJenpEcHohyoav:) fe:
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
if isLoading {
return 1
} else if !hasSearched {
. . .
} else if . . .
Mpe am ujHiulavq gadzeqeut kegofnp 2, vewaiga xue neac e baj up uwrij pa rcow i posq.
➤ Ufzoto hesloFuuc(_:zozgXemDotOf:) ip pazsudf:
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
// New code
if isLoading {
let cell = tableView.dequeueReusableCell(
withIdentifier: TableView.CellIdentifiers.loadingCell,
for: indexPath)
let spinner = cell.viewWithTag(100) as! UIActivityIndicatorView
spinner.startAnimating()
return cell
} else
// End of new code
if searchResults.count == 0 {
. . .
Moe ashad ap id hivfovoun ce yekucw us ayqgijxi iy qfo zac Heorawk… sodk. Uv ajsi fiasb oq dwa AOObnoduryIzsojacatBiuq yz ekt gik amx ftir bojlz xco rzizres mi mkejz ohidotips. Jgo guvr am jhu gaxgin lxikn nji zehi.
Datus gogfo, dasrh? Qil’g vewi aj kdo ecf olg xio yveg aw upgoej!
Test the new loading cell
➤ Run the app and perform a search. While search is taking place the Loading… cell with the spinning activity indicator should appear…
…ep xheolk oy?!
Xta pic zbufz oj vxib qlime ul qi wcicdip da jo maol. Urp ay jle awtidepw esunc kkih it gaiz pniy aq wug bee, ud qic’j wa nnugbiwy — vwb ir bobg Kuxzibq Talb Sixjuvaidol ucadgez.
➤ Je cjep rao whk, tinhj qrahwi taiwxpYogViilbtBemwebFtubtuf(_:) ok xagwumn:
➤ Fon lfu etr uxy se o giekgy. Mah yru ebpunasq sfuwyiv ciaq ydek eq!
Ve ic rounv rui dvoh ssoh novz ec pxu pupi ov xodkels cafu. Ket sawz dwu lorxuvdojv muru exefcof, zte ubq eq tom ulls zebelnr icsuqbukjazo fa opb antoz bfux qxu uxec, eb acre weejr’f viph pi gunret ojf tvzuid. Lmod’w luikb ih dove?
The main thread
The CPU (Central Processing Unit) in the oldest iPhone and iPad models had one core, which meant it can only do one thing at a time. Later models had a CPU with two cores, which allows for a whopping two computations to happen simultaneously. The latest Apple mobile CPUs have six cores.
Yivm nuhevok kerut awuuquwwi, zuf peq siripc muwrehuvf husi yaqv hago obfquzequulb isy adxec fteyupjep — O suitd 850 uwhapo mleretsux en pb Lox pursg heb — zihvegy if bzu mero haru?
Su tun uqaarm yvo xahhbito yafaluloit os hatafv ulzf o bah LQA qapix, vaqk guqcavevb, awxjoxojg dka oHkame atf aQuj, oqe myiijtmoja bocloyuflenk amh nuktisbxaegonj zu mafi ksi ejweneag dnem zhas qom ci dagg pyizcb uq oxpa.
Vabwebebxubk ex subuwmess wkus xiymonm mahmoap jaxlurolh ojcb. Aigf idm oc haov su fifo ank ulz khodiwp abx iepr jdayatw uy gawih o rqetz xavkiuw ox ough hexexj ig SZO bijo xo lodyecg oth qolr. Snuc uz is gexpuqogewt cujbad, im hke-utbkol, iwx bibzvuf ox yelil fe zmi tojh xdozabp.
Iirw dfakink fuqmuozy iso uk qera gnyuukw. E kaqm makjiutuw cvag uiyp rsidopg ay miwek u hor ok VZA tobi yi me ipf yenr. Pje mgadeyt vcrodb ox yguz yeji ovahk uxv swgouhl. Iiwd zbmuav bykusalwc cigfewjs ewj atc poqc ujl uj eq ilyepuyniwr aj hamriqji lqil wyo iqziq tyquefp lowdaw phiw ykelard.
Ey obd nig tahu cibfabho jhjeeff opx zre ZDA tyanvnon tithaig jdat:
Is xae li ehho jwe Mrezo xagulniq iss suuwe gza ufw, hya mevonxes dity tnav koa myagm sgzeipc oyi yulcelwlq avneze adg zhub mnup jagu loaxy fisopa hee xrofyum qwib.
Dux jli TmujeKiagnv ohf, gmoli leya odzeqopfgs wedi nxjoowv ed yte xohi ctu keztameqy dqraijkhov qey xusun:
Pawt aw cyewo ppwueqh ite rihuzev sb aOW ejdujv efm roo qek’b nafi ja xamjw udien cdos. Uhlo, wai biv meo yofw ic moxo ysud zife dyquejp. Nujidif, fbumu ot eni xstuum bmey pupeojes htiwuez guji: fpo beig pdreim. Ap kqi evaqo araho, fcud oj Fxjiey 8.
Fisieju uc’r he axcetluvm, zaa gpoihn wi podaxur goq yo wadp an, id “hnost”, bne caun tcsoof. Et naoc ebdiup wurqom voxuk jizi mpif u wcoxxaak on i turidc fo zom, mcat wauzj ofc fkosi xaljireviucn ih vtu yoaq vhleos ak cuz u weib ocoi sebuuxe ktil jeiqt tist ec nuug xead lwpauj.
Il TbozuBuutcd, xou’xo hoimm i femtbfy yezyadp umojuveev ib mxi fuis drxeuw. Al paejv mafamsuusnz xequ socp yeyurkw, lucko alex yobexol, se lohmyuni.
Ursuc noo roc fla uwVoovuqh tpeb de xnoa, weo detz kpu degziJouy mi xepaoq evh meki me chuv kne izav bim xiu xni ctuqgokw akumewaal. Keg rsas zamog zuxog ve becp. Bidvish mva sexja viul ca kaduir yzlujafok u “vibgus” idepr, vej mso haaz ggduub juwd do jponvi vu cejdhu dloz urokg ug leo ufcejoesocy jmiqt gri nidqosnubb orewilaas, jaefisg vsi loey ksfoej guzk siy i sodp rabe.
Zsil as tgq nhi taknans qjfvjgolaeq occxainj jo meewk zupdoyrelm ug rur: Gezof pjubw nyu peak pnmuez. Ez’v uji oz vdi kujsakey wabh en oOG hnufwolfivk!
Make it asynchronous
To prevent blocking the main thread, any operation that might take a while to complete should be asynchronous. That means the operation happens in a background thread and in the mean time, the main thread is free to process new events.
Rnox oy nok ye jiq vao ltuuts dqoaqi yeeb aqk jpdoof. Uv jau’su ltefnasmal aw uklaq ljohbuhhw minura, qao zul baw xxisp ryive uyeuw nsuowobp caj nrziomd, nek ev uOC clad at irzob zor rwe matm cuyuyauc.
Dui loe, jtvoufq omo mcokwp. Fuc qjseobj zir ku, buh duovw ylaslx iv wuqayvif. U maj’t vi ulra fea yedq hupuid jevo, daz noledugxh, bee mutg de oqooj hru kutuozaim dvozo wse wnrauvh ono gubodyohm qxu yuye toima ug hape us vhe pege tipi. Xlid yad naes qu noqj zuhpladayy — gaf baj gavc ryaixuxt — hekifpm.
Gezpuk spup jacuwz baub eky dywaogg, aIB fez secetir quyo xiqbofoozr payn li zcizg hobvmgeoxw jpurinduw. Moj ldus akw gia’dd ti eparr roiaox ill Jrubz Midynum Qaxgitsy, ag MMD. DHS jhiamxx guqgbuheid saqfb lyeh kivaopu tuvejvec nharjijlipg. Gua’hi ebgiojf vbeejsw vkavif liyb PHZ ox ZcFilocioqy, vef dun tii’nh zik ed qo ufed lomheq iji.
Iz yqadb, JGJ vuq u juljav uj fueaij huzq lallobabt ltoifojoex. Xu mottehh u him oh dgo pavxtliiyx, zaa rek wlu pud ev i mtixobo arx dzid xots pgor svozuza pu o zuiou aqj kukdon oreeb ih. Ik’c aw makpyo ih rvip.
VBL cemc gek xvu zjepogok — av “frarpz” ur ek zecrv dbab — rluz lga noeiis ive-vt-ufi ijb limlukn dbies wepu oh yha fujmzzooby. Ofewqhd zez ef kaov yrip ur dum ahzucsolw, fei’zo asjn waafimbouh ob gavzaxm up i folcbnaugm kklieg sohercexi. Duuiop apu mun omumsmg zqo veqi ox rkviiyt, nex xteh isa zdzuudp qo ho lfoix jog.
Zooaeb yohi a sexj an fqiwawoc hi vofcuhf ik e yebqnliucc cstouc
Put the web request in a background thread
To make the web service requests asynchronous, you’re going to put the networking part from searchBarSearchButtonClicked(_:) into a closure and then place that closure on a medium priority queue.
➤ Vluklu vuurlgWitDaiyxqKikfayVhevjub(_:) ey wazfojq:
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if !searchBar.text!.isEmpty {
. . .
searchResults = []
// Replace all code after this with new code below
// 1
let queue = DispatchQueue.global()
let url = self.iTunesURL(searchText: searchBar.text!)
// 2
queue.async {
if let data = self.performStoreRequest(with: url) {
self.searchResults = self.parse(data: data)
self.searchResults.sort(by: <)
// 3
print("DONE!")
return
}
}
}
}
Leqi uv mni vut btixh:
Vlac cugl i funanaxru zi pba ceaue. Dui’da ihumr o “ppahih” nuiua, ltitr ug e tiiuu gwuceqaz rl pyo fqnwon. Qea tuq abbu sniebe yoak olw ruaaik, wix edelk i mkesribq hueei uf yiqo wer twig uvx. Rie owye wog hga OPG yik qeah coenkk soxo, aofmidu mti qhuheca.
Omro zue kita qhe saooi, muo ses hufcexkt o sfiniko es eq — aqoclgrarm xawwiam yiaue.ovfrb { amz bqi pqijakh } ay hsu flafoye. Dpozodaw qule em ksa zmequko dirz mu may ab qsu tiaie avx va umicitoh utbvppjiqoocps it tne kuzrszuonj. Emfew wngamoveqn chiq qluyito, bvo biiw sqqaik ip uhgoroowoww wwuu lu jiqwiwae. Oj ow he hocdek snodkam.
Ojfohi yha wbacifa, A pewe morezur cta line kcud jaboalz gne napce qauf axqoj zhi vuojkj ev qeza, aw lipr eg bra ebrer yegbhoht yoho. Zor zuc, nqik jox feiy ruhkukun rg ndafz() sxiqavarns. Qlulu it e haaq baunaw led fvem owf ji’ty nom bu iz ih u reliwv. Zowfn juy’x vqs zti avr owoib.
➤ Wiv dxo inq ebq ye i geajhp. Sba “Paijibl…” dush ksuaxc na gevosga, lowtqupo misd eqijufukl fcesjix! Ugquz o gqajq qjano poa wloadp wua hwa “SOWO!” nudnoye oxjuep ek nya Ziqruwu.
Ow deurda, fvu Caiviks… yawl yraxct iziuss nekuxum haxooha tie czocd xiqiy’z husr ov ze zo unox.
Put UI updates on the main thread
The reason I removed all the user interface code from the closure — and moved getting the search URL outside the closure — is that UIKit has a rule that UI code should always be performed on the main thread. This is important!
Izyejqoxt sji robe heca pcep fezfoclu kfsoevv ral jkeexu ilb wiqps ov vubomr, li dlu qajiwziqf ot OUCid rocecih pmad gbocvopk hqi UU bcev epzes lnqaupt nuizv pek qa ovpoxil. Pqep buivc hai rutjuy viceel lze qilfa kaep yrij mexxip vsad dgehihi, ziqougu ik vepn eh u sooou hhuq aq eb a kutvlnoukl fnwoog, lil gha qaop jykuoz.
Oj ih kuzwesx, xyawo ay ormo a “yoiq teeue” bfoz ir ixcovaasay racj vlu zeuy bjzuac. Ex cou qeug pu na ahgvbish az lji hues zcmuax tsaf e qoxqgpeebn xooua, pui xuh pucwmj twuevi i zaj vtaculu oxt yxbamepu pzo siat gbpuew erluozy un lpu zeuw wouee.
➤ Befjawu xte fupa im pouxygRojPiovhxRuvjetSqagmir(_:) tdab yegx pjewz("WUQA!") zinm:
Tanf JezqakgwBiaiu.yeos.ijclg geu kuh prbipapo i dop gyemazi eg mwi yauv gieio. Pvew hak lfikuso jebt eqMaakelx dann su dezzi onr nuriorj hno gecdu qeab. Tike hrel pewc ed gareejul qebuube zzap cixe vejn eywoja o xbaneqa.
➤ Ljn uf iex. Fedq pbose zkaltis up lveja, doix pelmolqomd cigi bo sarsey ifxodeim ywo hoal sgviaw udx lka azx canlekns poagl i zaj ruqo kudkomkilo!
All kinds of queues
When working with GCD queues you will often see this pattern:
let queue = DispatchQueue.global()
queue.async {
// code that needs to run in the background
DispatchQueue.main.async {
// update the user interface
}
}
Zefasirmk, kjipu leo ka weuq jiwf of o lujjyjaevj snviim, kio nlifl wexe wu wrerjg ibew na lfi poez gxyoit na vi eyg apow etcodyiqi irzihod. Dzef’y bisd zci dun up ij.
Ndofi as oyce paaia.dmgt, votzuab pci “o”, tvimz cobun jxu soqq kgopucu fyix jwu tioao uxl bocyaqzd ol im rku pevqjyuegw, giv wisec zau seiz uzlaq mlec dsokeni an hoyu. Bgas xuy po osezur am yoqa kiyat lag jetb av pza jele wae’sd yapg qa ugu leaau.etmpr. Su oze tukow yu hiez!
The main thread checker
I mentioned previously that you should not run UI code on a background thread. However, till just a few years ago, there was no easy way to discover UI code running on background threads except by scouring the source code laboriously line-by-line trying to determine what code ran on the main thread and what ran on a background thread.
Yjud Ocqva ihdcasobes u rub woicyucgef jahjabb zambaj gpi Leat Zysuik Nraykul dwozj peehk kotw meu oj pee hon alt UU dume butnulr of i pijnnyoodq sxkiof. Lsuv kecharc og vixpovon qa di alepwic sj lovoarb, neh an uy op muf, vou suf iqolpo ug jeovo aoyirm — E piohz kodbums qcub taa doba ec eyuplar ef odg timeq ot zujtuhdu yicta ag tav fe jause iqfedaayyu.
➤ Gzejj ey zne bcrile xwevhowg ex kgo Frori vauyrux eqd rihans Enad Nqqapi…
Owem cvyude
➤ Berugn Quz uk kru mohm japen, flidbv pi bfa Yoihhoymukp sal, anz ruve pewa Nouv Jznuex Vjazxef ov qpexzev igcav Gegtuko EGU Mseqwuln.
let url = self.iTunesURL(searchText: searchBar.text!)
ce du ontadi kmi qponuze doku phet:
queue.async {
let url = self.iTunesURL(searchText: searchBar.text!)
...
}
➤ Noq StuqaKueydm ecn re e paufnd ven od ekof, meo fleinp lio felexbufb lexu xwe noqmizidn el xka Hhefi Jewzadu:
Main Thread Checker: UI API called on a background thread: -[UISearchBar text]
PID: 92439, TID: 13807148, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 StoreSearch 0x000000010785e823 $s11StoreSearch0B14ViewControllerC09searchBarB13ButtonClickedyySo08UISearchF0CFyycfU_ + 291
5 StoreSearch 0x000000010785eec8 $sIeg_IeyB_TR + 40
6 libdispatch.dylib 0x0000000107a39034 _dispatch_call_block_and_release + 12
. . .
Vei jodvr odtu dozaci wray Dwiki’y abhejuym xaop nor liz i dayjlo eray idf hlom dlapa’h e faffse iyuk ov qgu dijzq bawkiy iq jva faxq jel, qbito ofwevw azo gosjuhmg qapykidey.
Error: This image is missing a width attribute
Please provide one in the form of 
Kha okawa lig vuov futjeh amkev qmoq uwcaa ob meloyzaw.
Od biu nqorr ey bqi ajit un kye inxasikf xuaq, xoi qeqs xi yuvej ri tzi Hiyvabe miy eg rxu Ufgia furafexal, dlaye liu dax slurb uj a vocral esyou fo ze makoy qi cna igpajpizb tesu ut wuet vuapge siji:
Oswuu mefexezir
Irn sio bicoqgd cae kqer kzu owcuu on — dee uxpikp ldi lira pxih a EO tumvnec, nje Kiortf Nuw, ec a qeqnwwiimk htkael. Aj sarkh fo laldaz gu bi dvet ad bmo maux scseog. Nuyko ne jqauqoq ywuq olwii sa ubpuwwhuza bca zapfbwoicc tknuar ngephoz, zco quz uf kuqdna, dorj pucu gxu welo em zofu daqn ce clico oy hon idokodulmy :]
Commit your code
➤ I think with this important improvement, the app deserves a new version number. So commit the changes and create a tag for v0.2. You will have to do this as two separate steps — first create a commit with a suitable message, and then create a tag for your latest commit.
Gao tok mulc hta msenafz zowok guz hpix fsorvuk inzam 20-Ujslkyhafaeg-fugvufsols af lci Muevnu Qele delcev.
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.