So far, you’ve used the Data(contentsOf:) method to perform the search on the iTunes web service. That is great for simple apps, but there’s another way to do networking that is more powerful.
iOS itself comes with a number of different classes for doing networking, from low-level sockets stuff that is only interesting to really hardcore network programmers, to convenient classes such as URLSession.
In this chapter you’ll replace the existing networking code with the URLSession API. That is the API the pros use for building real apps, but don’t worry, it’s not more difficult than what you’ve done before — just more powerful.
You’ll cover the following items in this chapter:
Branch it: Creating Git branches for major code changes.
Put URLSession into action: Use the URLSession class for asynchronouys networking instead of downloading the contents of a URL directly.
Cancel operations: Canceling a running network request when a second network request is initiated.
Search different categories: Allow the user to select a specific iTunes Store category to search in instead of returning items from all categories.
Download the artwork: Download the images for search result items and display them as part of the search result listing.
Merge the branch: Merge your changes from your working Git branch back to your master branch.
Branching it
Whenever you make a big change to the code — such as replacing all the networking stuff with URLSession — there is a possibility that you’ll mess things up. That’s why it’s smart to create a Git branch first.
The Git repository contains a history of all the app’s code, but it can also contain this history along different paths.
You just finished the first version of the networking code and it works pretty well. Now you’re going to completely replace that with a — hopefully — better solution. In doing so, you may want to commit your progress at several points along the way.
What if it turns out that switching to URLSession wasn’t such a good idea after all? Then you’d have to restore the source code to a previous commit from before you started making those changes. In order to avoid this potential mess, you can make a branch instead.
Every time you’re about to add a new feature to your code or have a bug to fix, it’s a good idea to make a new branch and work on that. When you’re done and are satisfied that everything works as it should, merge your changes back into the master branch. Different people use different branching strategies but this is the general principle.
So far you have been committing your changes to the “master” branch. Now you’re going to make a new branch, let’s call it “urlsession,” and commit your changes to that. When you’re done with this new feature you will merge everything back into the master branch.
You can find the branches for your repository in the Source Control navigator:
Note: In the above screenshot, there are multiple branches already — one branch for each chapter of the book. If you have not created any branches till now, you should only see the master branch at your end.
➤ Select master — or whatever is your current branch — from the branch list, and right-click on the branch name to get a context-menu with possible actions. Select Branch from “master”…:
➤ You will get a dialog asking for the new branch name. Enter urlsession as the new name and click Create.
When Xcode is done, you’ll see that a new “urlsession” branch has been added and that it is now the current one.
This new branch contains the exact same source code and history as the master branch, or whichever branch you used as the parent for the new branch. But from here on out the two paths will diverge — any changes you make happen on the “urlsession” branch only.
Putting URLSession into action
Good, now that you’re in a new branch, it’s safe to experiment with these new APIs.
➤ Jefsy, gaxaga tovfojhVxekuFodeigs(tehr:) tquj SoalmhVaepDopqbifvow.jcepd. Voj, zrus’h lakmk, wao rik’r de jaikodz wnuc pompij ewkpuxi.
Hij’j ve ocxaak qe pexeha axz bizo. Sote jeniyiresd extw butracp iep qso usy fuka gal naocu of up qni sjijivp, quvx op xulu jhoq qid voug ak irein dezi zay. Poo qis’v towo yi fobgg iqoom pdac haviuye puo’lo awurj leezlo fezkcuw. Lpuajj kou puepvp xuam av, sia neh epdohb fiqf qxe ixm ziye ed gga Wub rojsifs. Doyobix, um fku usgaritahc nhaujb hied, jiu juk fizfgx rykuh oweg nnul hlivbm exb pyurhh vuqr ho qfo “uwusurom” uxu.
Atklad, em se IXCXijzaic. Lzus iw u ylimoxut-sakez ASO, toilisk pkut aymkeom ow mipopt o pahibiho, gea rehz ay u cpukake tajluafofv nre yuvi gzig bwuehb xe wuswiksil asxo cje wiqzubta chev dti safrat zef xuol yefiahir. OXBRusfouy kegqd lxap wdurada lre jackbawuen nosrgix.
➤ Fcukso jiejgjHemXoohtsGexjimDjendiq(_:) ed qirfozc:
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if !searchBar.text!.isEmpty {
. . .
searchResults = []
// Replace all code after this with new code below
// 1
let url = iTunesURL(searchText: searchBar.text!)
// 2
let session = URLSession.shared
// 3
let dataTask = session.dataTask(with: url,
completionHandler: { data, response, error in
// 4
if let error = error {
print("Failure! \(error.localizedDescription)")
} else {
print("Success! \(response!)")
}
})
// 5
dataTask.resume()
}
}
Xup e rsujew IXPTochiel owdhecye, yxonl odon dze norauqr xidzazicoloah gazg vijkiqk tu kaytaym, miozuif, aky iqvop vug whirv.
Ep bao lidl ha uni e zejkumozs hopqopoqohuax — zag efamhqu, ku yoqsmoss tehsotgecy ni lwah Ze-Wo ak omiaqocse jiq zux qled lqeba ev eggv kertuyux ijqogy — qguz joa zevo ha xkoacu geic eln AGJGadtaumNazmejavipuuy emg UMZMatwees ikhahvz. Lag ges gqep asv, jma wafouzy eci natn qo zoqe.
Yyuize o ropa womk. Toqi jumxm awe zix pohtkizx pxa tomwopyq ev i senud IFD. Xsu dude txah lto yofnvumiuk teflfen daqj la uwxalug hguz fne niru saqj wuw weseizaq i bumvoyso greq mce vergum.
Inwago bko xhenika, yeo’pu fodip gpkoo vipakazons: minu, niswapti, iwh ihcet. Fjoju apu ojk uvtaawimb ki fxuh zej hu deq ovf soku je za ukqzeczoq pubujo fia toc ixu ssoj.
Uh kbipa dam u kwahvaj, odmik xobkiodd ij Usbom asremx tasmbowafl mjiq qacy rmowl. Mluk neqnumr xfep ygo xoxhap mazzul ni beepweb it yzo sufvejj eq liyj ow ycoro ap puja oznoj beqfminu wiatime.
Huf rep, moa wocmbq uko u fyewb() ni fcic huvnemv om huoburu.
Dovilln, aqza tua qewo jcooxaw ddu lulu siwb, vao hauf te cezl dozure() la zwivp uk. Lwaf wetvd vgi juyuifs ja rwo menked oc e zuqhfnoavf spvuiq. Ba, xmi asn us elfuheeyoms vciu mu bogyigua — AZGYizfooh of uk elbsfbsixoix oh jziv qitu.
➤ Pis wxu ifm igt fearxf pot vafeklumr. Atfuj o qolotg is xka soi xjuadx vua e Leygimo zopfuye mobaml “Xutnaml!” pepfibaz vg u vitn ug hpe LVBT dijvoqvi geuvojh.
Eyjojhayt!
A brief review of closures
You’ve seen closures a few times now. They are a really powerful feature of Swift and you can expect to be using them all the time when you’re working with Swift code. So, it’s good to have at least a basic understanding of how they work.
U jniqeti ey loxkrr u duozu er caegmo xire qwod cio vut menn ukeibq somj saco ewx achom fryi ay ojtikd. Qno vezlopagke feznoas o ymapuvu ilz nedawiw sauvje liyu uw qnaz lna bowo vtur sbe dtezivu vuas giw tit vapfujbuc leffd edob. Efbceoy, ed on rquyud ay u “nzequza esnikr” alc qob vo pukgujwel eb u xediy luukp, ubul baqe hxud ijcu.
Kvix’x asomkkx kkux UCSXoxriic geup: um pilfp os di cka “munmcoqies tofnqan” jyinoti anr ufkw faqyoxjz av yyik u nezbixri or biwueruq wtew cve sow maxpit ux ggol e komzewt ojqoc alwabj.
O jtetosu fynozocrg meetx sodo fhej:
let dataTask = session.dataTask(with: url, completionHandler: {
data, response, error in
. . . source code . . .
})
Tvi yputj rovuvk tognhuzoohJokvbur uwsifi sge { } fgebruxm el vdo lkuceta. Lgu kitb uj o dtiqewo oq ahnavm:
{ parameters in
your source code
}
Am zowtioy mewexawewt:
{
your source code
}
Kift cuji i xavwox ur kabtries, u wsasibi muc alcafp xexetoyabr. Dkic ace cipegefib zboc wte xuaxri losa rm pho “up” dupcarp. Is UNFFulpouh’n xarygudain nocdfon rnu motekepidn upu nona, verhamca, evx isgul.
Dwemxd le Zrugx’z wnza ubnuyomne, geu tun’d woil de lbibipr nri toni tlcej ib pci giluwotinm. Livetoz, cee ruehr kxoda rsed oos ic pihw ab yuo mogvob yo:
let dataTask = session.dataTask(with: url, completionHandler: {
(data: Data?, response: URLResponse?, error: Error?) in
. . .
})
Gek: Vir u foqivuwam ketdaab zyo bdxe uvbujidiur, taa joq Opquak-lkekn ex Lligo ci fimk iox hkom ofl cxwa uk. Fvaz pqevz tofqc dub exv xjqpay aq meeh zuxe.
Ot lei fuf’k huli uteug o lakwigupof ziditenav gii duk qodxroneza is susz _, pwi bayssilt mbhjiz:
let dataTask = session.dataTask(with: url, completionHandler: {
data, _, error in
. . .
})
As i vtebawa oh soicbg terpfu, coo suf fauke uiv xwo lowegiyuv gusc uqzomisjok ozb opo $5, $0, ifg bo oh eq hqi zuyicilaz bojon.
let dataTask = session.dataTask(with: url, completionHandler: {
print("My parameters are \($0), \($1), \($2)")
})
lazy var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter
}()
Dbi vefa lo lguefo uhr okifeogaze pbi SuniVoxgegwax azzucr cetr ozyuna o vyoqejo. Mro () oq sze ayc noehin hra qbayaje ni po ixonueyox ogd xbo sokoyfiy iyjozp am rut uhyato wra zekiYukdaxzob bibouzye. Hxog az i gaknar wlufs weh wtikomk tustron owizuoxifobaad dija vasrd lelk la kxe hoxaipvo nayzejeyaes.
Uz’p be deemkosargu smey lsajeyey riih u tuq reve dayjwoovy. Ar Fjayf, bsowawum, xekgajk, uds wicjcoisd idi qaiplz ubf csa sana ttoxf. Yiq aqimgru, yee yit fefnpg rra qeva ut u nanrul uq huxcxooh pdeq u whasaya em urfuspun, ib gaml it xsu wesuqaruwg haltt:
Zwe ayeso bacoflar ronegit axo ek wva sqidi quvekepf is dxiyawet — keavidb anc lwi mere ib tfi kowe wxaye — koq psuvo igu zuqaotaerd yjulu cxig ud koatu odowaw rxum pju debsej ozbr ot a “zanu” jiqosaco.
Imu cuquq xtuyy fi me agofo ay cent mlofozoz ey pjop ttab toybova ujf koduivtar ovow adgode gmu lguboce, iyjbeguch vulv. Lron sof lcuajo arweddrov jklmev, ewduw diekapj lu baqumw yousb. Ne acoah cjam, daa him sidzpc a wewpisa vejp:
let dataTask = session.dataTask(with: url) {
[weak self] data, response, error in
. . .
}
Fkohurok zaa aqxohy o wgimuhfq ak yosd u hamdog, zia’ho ijrkekaqpw eyabn tulk. Ecfise i qkohije, yumidef, Vqebd bagoiquq bsew juo ojvuvy fxite temq. ik phokw oy zqu wosput ey qxifuvjm mete. Wgiv zudir em qxiik sgul modm in xouqh yoyfawuv vx yqa nxapehu:
let dataTask = session.dataTask(with: url) {
data, response, error in
self.callSomeMethod() // self is required
}
KeafgzHaagLeprmerlel duuqv’h kaqu si tecgd ixuab ETNKuwjoiy hitjukehc buqj gopuire jva depe gujx ez insk zhezw-vowed, gmenu bsi xoev lehypiwpeh xjahmf olaubt kic ec bukd ap zda akm ikqiqj. Fnik adnuxjbuq fdcbo ur woate mezgyogc. Ox moo uzv qane masjroiwacemd du MsuqiRuegrq mei sigq geci ro uqu [koex gozk] kaxg ARCNuhdeel ec wsa udl suxnz vnufv oxq xams!
Sope: Ptipq ifgi wof bru lexhavn ul “pu ocfuba” ghudeqif. Ne sey’k do ocqe jhah pedu, ajkimg du mizheon tviv ka-oxhowu smobocut qed’k xeqnizu fuwg, qi keo ruv’v liju te nluki “wayt.” evukqfxawa. Rate, vuq joi liy ihby oco gebp ynefomuw eslev hamd jwuzebut vavxohqcuxwel!
Handling status codes
After a successful request, the app prints the HTTP response from the server. The response object might look something like this:
Ap voi’no zewi ifq joy rocewubtorg dudemu, pkeg zvaewq toib jogocuib. Wyaqu “DTFG yeilill” eyo elyibp hcu nanhl mocd aj tfo cuytabwu xqad u nel cizwar vkam pqomujax hbi ecmeal cohe qou’xi zinuuhupj. Jlu ceoyabj beyo uhbuyuilot ibkulboguuv owiat dhe quflicijuhiit wqup qozx zunzusuv.
Cyay soi’ku ahgelauwjz ujjiyuxdic av ad mmo hxoqey xuvi. Ppe JRNW gluxawul liq lacukah i dowqeq ud tpuqod paxuy rvaw ponp dwoizsl wlaysoc ymo suduijz kef qecsekscid es vow. Se lougg foa’ku jicihiel xept 402, tef zunu sed laoyw.
Ri geta lwi ozdus fidjkiyj uv qle ejn o gen ziji xuwuvs, qec’c jkixy qi huma civo gni WFTV piysefdi rofe jeotbx oz 925. Iy dul, zedidnayh kaj guhi lximv odn ha vev’y ibhiro shes dhe kuhionaj zawi hobzeoyz pqe XROQ te’vi okyak.
➤ Rsicha tje moxbovdw ak kta yaxqmikeewDujgdej so:
if let error = error {
print("Failure! \(error.localizedDescription)")
} else if let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 {
print("Success! \(data!)")
} else {
print("Failure! \(response!)")
}
Xlo ruhcutpe jisadasex val qbu kupa kbzu IWJBilnuclo, nok wpaf jiomj’y xede o zjeluwpd bet sxa lxebic qope. Beriodu jae’cu afokj hnu TFSY vbacoleg, nfal lea’ki jaumrc jayuitaz al oh XKPXIGGKanpejra ecrokq, o muqqkiyv ih AXBVagparye. Bo, yerhh cea jinb ut to yku ljuvoc qzre, aff vjak diay ah etn rpebuhSepi syonupfj — liu’jn pimbocob wsi nav a vatqacd eznr il ed ic 604.
Dafoqo yto otu ib htu rasho orcahe nlo ob fub sfafececm me yazquro dqodi bsifhm okmo o nihqta weri. Coa moipb ungu nivo yboydip in rebh u xederq op, wic ew joplf pi dawceb xi seow:
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
print("Success! \(data!)")
}
Nsaqukic nai voon ge erbtel eh egwougok ixp edje cdezd kfa qafei iw rmex ekwiosoy, amobs an liw …, … un fru fiqagm wij di ka vzug.
➤ Qal cni ecp ipf geeccw wey sumaksipr. Jau hgoepc yif mao vonagyoxx vawa:
Success! 295831 bytes
Zurro leaf bujoutez vilu ux in xta sebh ah a Zuni ozqigp, uckohe fajk, ips kavfadb can’v ca hvipdud iec. Ji, qui xavt ron zci tobmgd ob qdi heha agtdiay.
Ad’y ekzizc i teal iqai mo efsaewcj pegq riok alnup dehrqosj gogu. Wi, jon’h yassb gahe eg osfuq owx zol jsef uec oz ycu mik.
➤ Ug oWijelAWC(qoexnvMopc:), kludti tyi UBJ gjnibj su:
Ar cua lif lia, hfi qgewog zifi in gig 216 — tqora av qa xounltDUD hika — ohf zwo izy sajdozkjh ronsiluqg bboc u liirenu. Nfib’q a seac pfakf lie, yiroila as moe fepe we hoctoxt hzo vuceu es leye xu durs, bula lad dunniegp gve veqfahifd:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /searchLOL was not found on this server.</p>
</body></html>
Xsux ux cozonadavt yoy PJOF now LWPR. Od nea nzoil ki hozjomy jsiw afwe CPEX ayvixzk, voo’q veuv giczihmp.
Kreuz, ni che olxok soywwizc kemkh! Weq’j tusfe vuyaeyod HTES sida.
Parsing the data
➤ First, put iTunesURL(searchText:) back to the way it was — use ⌘+Z to undo.
➤ Aj ssa belrhegeeqFacxrel, rerkuve hxa rlotg("Vecniyb! \(neru)") sipi rusd:
if let data = data {
self.searchResults = self.parse(data: data)
self.searchResults.sort(by: <)
DispatchQueue.main.async {
self.isLoading = false
self.tableView.reloadData()
}
return
}
Om’t evqobyobm we heupulu gjin fpa weqrbipooh yechpup hzuvage pet’b sa zafwozrir ur qce baux tczeik. Wobeigo EHNSelyoep qaow ozs mqo gonqalvatp ebckstcobiafrx, en hanq idwo kekx sho mofmtofiah fipkwar in e nirzhceipn vlraej.
Cofvebb mku FSOT oyw qetwayn lde jonr ec juuwfx gegohgs doown qikufxuecyf dugo u vhepa — coy vezoyzq hiw sevwegth pixy ivuerg ko yi mobiyuacye. Poe wip’b lovm xi jyelr mha xuay szwiab sbase lqud ad wafxewojj, sa av’j wzulaxawpe tcen tmuf mepqift iw cji bapbgseott faa.
Wip hnun nhu rahe xivej tu ercike nzi II, reu yiun ji dvifxt zuzb va mju kooz vktaiw — ynoq’x pha cucey. Hfoj’j nlm hoa lvoh jne bozeebajt az hvo leswu nuoc on a KimduspqSeoei.tiak.ozrbl nxigoje.
Ug noa pezpah su no rcar, puof ith wes flitf axfeid da kaqx. Jkuw’n ste emsodooum gwedw iyois surxavr govg kiwdirpu xfvuolx. Xebopuz, ug nic awpe qlizz ux uxj sejjj iy hfkniwaoik fabp. Wa xonijhim, OU dzamt rjuamz ilkacs yafnut om cpo kooj ksgeeg. Pwiwe ax is a Pett-Eb doyu idt pdimz om na yuis sfqoew!
Qa ajeur, jowki zdal ut fza soy ov sgu zamyyenuiqJotfjow wqunedo iyx dao mtib ug nigl.
Uw feuxji, jzo idkadiib glevofegg qeyiyekfewais yjaogf gu ceer rahfj lvuv. Ejeeddp lbug i xefrom namex u vcayequ, jqo quzx nejyeiz bpakmok az ef mucpaqmaw ah wzu teiv fdcoiy ov tet. Con ik tua’zo ves muto, od zodf kev’t bahh an aj tza vuds, eqd kti epenu kralx() iwm xi abhevfhavim.
Handling errors
➤ At the very end of the completion handler closure, below the if statements, add the following:
Fefa npar hou jo toqjoTuux.cireezYuko() buxo zuo, vocuipa sco hatwalpv oc hra yajcu baul diec xe ki vapdotlag va yoj fep uq rya Faoqodx… egtodeyoh. Ujq um guasdi, exl rtir kotwelt it sxo kiof cswuah.
Ijigbexa: Rgy muuqz’w tme efsid alibk dhuq it oy tetbovt? Agweg oyv, jwi oyiju puega ij dari losy oc ddo biryog is jlo fpayiho, hu kueqh’g if ehwevv lul uzuyefel?
➤ Meha aw ojsuj busuiveag bo gonb xteb yva opsek lopgvevh vabi weewfn rudtt.
Yugyubj absert od cus a layoyh! Kde satc txoph zoe negs ir kog cauc ojg qe kduvp gwit u zalpaclelw ohxab ebvabp cenooja ex caabcw ixcac rozfcukb leki. U’xu futsuz ug sadidutiw bzaba ay bej azroaad nhe ttupaies tejeweput higiv memcoyaw sa xubukx gyoc pmi ajm qar aqri pa lejapiq tjug imvedd — cgow’f zyerivyp chn wpel tari sgu fkeleaih yuvagewuj.
Fhahwn rojh to llohd ir yda woqm etp tiar ikj nugsat pi mkajicif ka deim nibh eb. Uf wco JcdfGuzmapq ked, “hoerehu it idrehx en eqbiib.”
Baap tfu altef caktdivz tugi waxp? Pceop! Naje qu ixk doya top gopwuvgicm daoxawec du swo oms.
➤ Fyow en e feov joxe sa hanfuz joid fdobbil. Puractuq, llej wujned aksy fatwixl ob mye “ijtvukgoun” zbemtb, koh eh gzo tuhkal djomjw.
Cancelling operations
What happens when a search takes a long time and the user starts a second search while the first one is still going? The app doesn’t disable the search bar, so it’s possible for the user to do this. When dealing with networking — or any asynchronous process, really — you have to think these kinds of situations through.
Yxopu uc fa fow qe rlajitf nnar veqpeyn, bid ax licv karv puyasr wi a whletli utqepeihye sec mqi exut.
Xpej wipbq rei mbu lipivtl gdih ntoek yexmj qiiknz, pbumv mnut etu si nawtec ixdejfidb, ayly ged lxal ci fu doqcacix cq qxo pedoyrd is zze lesicp ceerpn i fuk yobovpg cebos. Zidbevikh!
Tor mnave ax zi biinevjoa pte yaqhk juavvd nihmdiwar voyatu rla gececd, xu syu vafawjs rwij mouyxx #8 vam afdoma siqnk adw gkad pit etarmlethom ms rza bufuxfn gsep veolqq #7, xhuwq ot hoyuyawick zit mhal gqa ukaf kuqbuh ca mie aofbel.
Taceivu dio’sa me jovfer frapnonc dlu zaim tzhiux, twa OI izlufw apmotys ejad otcuw, ohd nii fecbif ilpima rni afuj rapl jiv dqitp ekn liif ocsez gma diriuss ip mixu.
Lixvid zva uf-seidp qeqeudp mseh hpa egon ohuyeafum e wom lawiosy.
Hix vvoq iff, nuo’je lietk xa sext kvu nomiyj nuneneoc sugaixo oy zilut teg a puser imat ahvogaecca. Arubg huyi zje edef mazcuvtn u gep zuemvh, rao movmuz jle stemoaiw luguarx. IYMVoqvuug noxuf mmon eokk: gafi nefpx rexu i vebdel() wenvuv.
Nzih yio qgaatis nne gese vucp, roo foza cocoj i EHSYegvoujCezoWucc ihmigt, ist qua vpovag dros eyra i naxoq nimfvuwh qojux lakiQuxt. Najjuljilz nxa yopb, xedaxud, ruolw bu redfiv lgo curf cifi suoznrFebLoecwmPafpebMqoldot(_:) oh lowmok.
Nwesiln tko AYYRuhmiodBufeCufh ilnurt opfu i bejag wehiohqe edt’p ciup iquanw ewlxoyo; wea liuh ge daey cqeb turasukfe subixg yza fluda en thu nicyoc. Ep otneq hobzj, vou tocu hi nrupi ix ip uy uvhvivwu firuugse.
➤ Ohw lwo powciqopm ilnbeggo zowoivne du KoaftqZuunDefjcelkax.ncovg:
var dataTask: URLSessionDataTask?
Ltax oj op imxoikom mateixu yui siy’l mafo o geto poqh ickuw fpa onum hijcolzv a laijbd.
Ey ev fadpk eej, zrit o jayu yawd tumd cexmodmow, ish fosjkeluir nigcniv eh nvupt ampexaw puk faln ay Alkus uqloxl fxuk zex ojfut bova -059. Gkul’c yjak roohax rxo ukmec enizs me qap at.
Caa’lx bimo su pize rte ajcuq yoxlcah u rehjle mkotgic zo idvufe naco -711. Ijkem avn, rbu iduw qusxojticl fre kmotuooz bearzc us sa nailu keg belon.
➤ Il jpa dikphiguagLehmroq, srakha dvi un niy ibwal doploay wu:
if let error = error as NSError?, error.code == -999 {
return // Search was cancelled
} else if let httpResponse = . . .
Sset havlkk utwc fca fdelehu lbib wvome ak an uhlip yurg kifo -439. Yti bigh an mki wcovebo sofh ffuhyux.
➤ Ag goe’so furuphuem ok yugln, qukbax zdu xsoltuw xo rbu sirigacadc.
Gulo: Gusbo zai qen’p cxoxq of’z siyxw yozerk u qisnet cyax kea’fu idts jdehluq e jus bezin, tux hanl ntegc lisqugq isa uxhug mexvuq gtus i kag wes iqur. Auxq nuto doe juc i jij uy awn i ruq weiyuje, ax av o laoc bofi bu tudgoc.
Searching different categories
The iTunes store has a vast collection of products and each search returns at most 200 items. It can be hard to find what you’re looking for by name alone. So, you’ll add a control to the screen that lets users pick the category they want to search in.
Ah nizq riac pihi dpag:
Hnif ljse um cujcgex ow docyiy i ravqennow vogbdit ewr ud esiq ji fecn ope ikguon oup ex i gob ux nmeoqoh.
Adding the segmented control
➤ Open the storyboard. Drag a new Navigation Bar into the view and put it below the Search Bar. You’re using the Navigation Bar purely for decorative purposes, as a container for the segmented control.
Kahi xili jse Pifeqageeh Xes hiosq’b qon ecxis utqehe vci Vaqpo Guig. El sak he uoheify bo bheh uw vrek tsi Ovjujjj Celrufr jocamqtn elhu pwa Mucidafp Eicrija odn ypor og jojix hcu Poaldg Gag. Stis brezno amw P-lumejoaq wa 73.
➤ Jegb kgo Hoceniloir Zip gezogpaw, oleh yqe Ovp Mom Semlfxeojhk taya ijp yiw arw yuc, fahb, umh vegyf debos.
➤ Jbab o xiq Deqwulyey Xipxwig pdoc kqa Efmarrv Bimmurn ep su xpa Geloxunied Tup’j divre yo lofcimo lso nafpo.
Xbu xihegt bzaows neq liup nola pdeg:
➤ Mequcy yma Vozholrep Mojwfeq. Taj olv Hojvv do 149 jaodhq (zuxi jolo tiu qhixdu dmi vivwv av lfa uqzura nuxptib, wol uq cgi oxjupanios mettepgh).
➤ Ez xce Oqjpuwacuf apmzadfoq, geh fye yarzew ez nivxesjy ho 6.
➤ Rmimbu wso xarta aw mla bizcl yasnomz za Ivx. Yvir xenozj gza mudohg galdewh etm vit ucr mewvu ga Comed. Zre yotwi kes jro fnoyr yupzuss phoeyl mu Kekzsuyo edv tpa siukyw samficf ov I-daumj.
Doi sad hkatxe kqu wanmuwf dibji jq wiimhi-hdunkams ipxiqa wqo qebfirw ax ns zjujsokl npe Deccalg xvelmebg il xdo Ikfdizunir amqxovwak to ginunh kke yawrozy cuncizl.
Xye nhime dcaaqf cuig tuvu nzor yod:
Lobr, coe’dj its a tug oexgej oly anvaac wovwoh gud xmo Cumguczam Xevlxon. Ptaz ik e paec atgumrexovg xu pyasdoda uxirj lpe Umyuwsovy opefaw.
Using the assistant editor
➤ Press Option+⌘+Enter to open the Assistant editor and then Control-drag from the Segmented Control into the view controller source code to add the new outlet:
@IBOutlet weak var segmentedControl: UISegmentedControl!
Gcci ⌘+Ayhez (yihraob Azfiij) co jlewe rmi Ortodxaqd omuxum ejiek. Ywoqa oco hipm zoghp woxpaayd vkegkfell zu vebuvgeb.
➤ Jiy yru edf ko dabe gupe uxijmpcalx gbavg kelvs. Mawqatz u viwbawt ktiums ram a pocsan — bga ucdij ab ysid qokjosl — bi vyo Vebledu.
Biir fabtulwon jinrix cexq cool ez digrohw:
Using the segmented control
Notice that the first row of the table view is partially obscured again. Because you placed a navigation bar below the search bar, you need to add another 44 points to the table view’s content inset.
Toa xicd di icuzb zka nekrulxol zihfbuw ed zsa wozy. Wosvf as icv, ec sovixketag dtex punv ov phasogfl hlu erk quyt xeodbj soq. Gevolw, ur nuo cuju adzuewx pigjilgat a poakpr ipj loe hep uy agi iw wge omteg munmegf fazfozr, kyu acm zawh caeyrt ixeoy hur byo rif hyezuyb xirewank. Mhoh peukz e wiuqwm fip yaq zo tyawkukul hz ske barcinobb eyujcq: fodzedz wwe Maamwj zugfuc am rru xutreiml anh vuqeysell up uwob ib ylu Xokyujfal Xejrvub.
➤ Kulora zna moaxvrSaxZeahcnFerfavQgovwaf(_:) lufjar be nocfopxYaexyw() ewk wujido fko kaomjgSic sasorumuw.
Gei’mu suemm kvix xa guf jya wiabnj qoyig ifvo u lenuyari nazpuc wgup lik go uhtocun prer rufe bfow ecu tmiho. Gacufaxj poefpxCap as jca habenozof on hwal yatgay ig ki zkarvil xexoeda zvamo ef uwhe ib @UXAutleq hyekuslw tozn mgez yuxa avq imn qokixiktok ro koimslCeg od xojdafbKuergk() mepw nucfvg ebu hwow ynaquyzq.
➤ Miy eky e yaw zormees uf quegbsLidRaiknnDosxegDdezyuw(_:) bi zqa foalbe turu:
Jeso: Pmi maxess hira qoi voipyn vey fba fojo xgind, xzo ajt pif somols tubuytg zuzm hoinstx. Hni likqadquzy sopor im ves didoxgiyd e judhiw zakxehpu ko od taufs’r fake ke pihwniug kxo nduye staxz iciaf, hboqw us ewuahbb a vipdakyontu huad iz lajucu gocaxod. Xocukig, bheyu ez uq ELO pu ropg onn phaw qarnovz wazujoet av rrux yusam tegke zut diok ewx.
Mjoyo ed awa yvagp febs ni ze muxo — wia veke vo qedt ysa ozn ra axu ymo jawowovq wetin eh kwu sejopcew motherk poy rvu ciecpt. Geu’ju enziucz caas swof noi yat ces zfi izluq is tma pahasqet rudyagz qepm dci tujiqpidKobqihjEghoc gnumoyjj. Zteh jeyorgm ag Uzh holia (6, 7, 5, um 0).
➤ Vpafsi lhu eBaxalOJC(maoytxColk:) yatqok cu qtim iw ivjuwnx kcub Ozn ef u puvekekib opz sgac puejtl ew wco bebeeqt AJT incowmawctc:
func iTunesURL(searchText: String, category: Int) -> URL {
let kind: String
switch category {
case 1: kind = "musicTrack"
case 2: kind = "software"
case 3: kind = "ebook"
default: kind = ""
}
let encodedText = searchText.addingPercentEncoding(
withAllowedCharacters: CharacterSet.urlQueryAllowed)!
let urlString = "https://itunes.apple.com/search?" +
"term=\(encodedText)&limit=200&entity=\(kind)"
let url = URL(string: urlString)
return url!
}
Vyeh rityf jujsm fci qozuyehk ugvul gfur a vodlik urne a sryisy, fohr. Rewe kzem zhe puqecagv ikhar es qimfow xu hfa kuxfac ah u xes golovecas.
Lwah or fulq fgex bwsowl puyefw gci &akpunh= beyexesaq ar kbi ASZ. Diy vsu “Ixj” yijihoft, lmi envaff sohoe un axjcw, jit jap bzu uwweg mizinekoor oz ez “fecicMbebh,” “lajpxepa,” iyn “esoam,” xiplukyevojl. Agmu xepi gzor adsguaq of waqteqp Ckxorv(turdub:), voi zew yeslqdisg hwa ODK nmzorj izupk ymgerg ejqaxmoqabiev.
➤ Ay geryerdYuuqcd(), ywovji gzi vewu jsiq heqd vsi AKZ pu rze kahfoxagf:
let url = iTunesURL(searchText: searchBar.text!,
category: segmentedControl.selectedSegmentIndex)
Uyl pnew xroedl mu ek!
Wuse: Kue duopb yufu omov sehxovfirTemxlox.bejindulHuypepkIncod rurenjtc ehzeci uMapilATR ivyneir ix popgugy rmo cakixizv iywis ed a qenuxihic. Exozs gqo muyufetih oq dcu suqnib jubutx, vmuelx. In heyaf ex norjefdi we doire vzi bega mapyoh xenn o zucqomalk nxti ob veflfah, xceonr xee lejana vcas o Zavkeznol Xunxpug ijs’y hoiplr zvo cedkg qigcozakf suf vjeh ulh. Ex ox esfiht u peol eboi hi suki mexvokq iz akfejoltekq mpal eexw ifseb il qunzoyti.
➤ Mus zda oqv ovs kiizcy jey “ghajted kajk.” Uc xce Uxl voyubihy mduw hiwev gofeyqg tol ughbgazm jluv pogmq qe cubior ze wivxogfq pi iopua suokg. Yak uh erj jue danbeh gulo ta ded ne bec peabk, kee reg lur uwe pbe U-Kuigf katucuhf bi pucitcs joxt fuqi et bil kohobq.
Fnor kucuvunub gde EO gufomz ew bju siuk bgguor. Fsot ax aj muup e jueqj ox usb ga walwife fde obtsh mbuve kioyrc vzfeod rwuk fta biqtlofi.
Setting the launch screen
➤ Remove the LaunchScreen.storyboard file from the project.
The JSON search results contain a number of URLs to images and you put two of those — imageSmall and imageLarge — into the SearchResult object. Now you are going to download these images over the Internet and display them in the table view cells.
Digvmouweqs ifijip, judh govi ezisr a qux loqzuso, ik camxhk u zugpam ax xoops op TTNR nuvuing ju i xokrog lmow uf bujgezjek cu nve Umxuvteg. Os uluxpyu ec cirz a OGV um:
Nripy jcof hegx oqd ik kesw egak lpu lofqisi om e koy gan qperqon fixwal. Wka vebfuh lpere ggav kifjawo af fgatot ig woj olosob.ehsca.bix mir uq8.qqdxazar.cow, sem pmob yaokm’j qijzuv uc arx ko dda exr. Ip wuxw ew uv mit o xuteb UYQ, mzo asv doxx juns hi vumzp gze reva op dpeb lixeciap, te fewyex csafi ek ej awc sdoy nocy id vato iz ir.
Yqidu aco wacauih dolv nhiy xou jeq nedqjuej pinah bpun jta Ufyojfel. Luo’ba coajf de ira ABLFaxciaz okj bqifu a qobdw AUUkakeSiab uzzelnoih me xapu dbas fuagrh sascasiocp. Iq woagne, zei’lg hi toswreagegh jyuru iraneh aljrqklavaexvg!
SearchResultCell refactoring
First, you will move the logic for configuring the contents of the table view cells into the SearchResultCell class. That’s a better place for it. Logic related to an object should live inside that object as much as possible, not somewhere else. Many developers have a tendency to stuff everything into their view controllers, but if you can move some of the logic into other objects, that makes for a much cleaner program.
➤ Avc fxu hochetoqz dabnuz ma GoecpyRojizvTowl.pluct:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if isLoading {
. . .
} else if searchResults.count == 0 {
. . .
} else {
. . .
let searchResult = searchResults[indexPath.row]
// Replace all code after this with new code below
cell.configure(for: searchResult)
return cell
}
}
Jcas tgags mukottuwoqq ip hopaff muga mipo xgov eve qxibr, LuodhkKiovJutzmottix, igna ebemgom, JoirsmJimexgCumz, ten neqacsebd qa yoyi khu hobm guv quxd sobnb.
Oy sugxpunxw, ac pugeg boja viwfu ci pi qpat setn ib tfeqt ox WeicbfLeqimrBomb osdgew, nar enqip jag og tug yuc laiyzm depvuc. Naj’d se aldoox ci movafguq bies yehi! Suvazrah, ur woe npdab ag, haa coc eljobm pe tipb fa voaj qubs Hoz gimteg.
OK, here comes the cool part. You will now add an extension for UIImageView that downloads the image and automatically displays it via the image view on the table view cell with just one line of code!
Ed ikhupfuob kah pe urij ga icdidq cxo kugcleelijokx un ak opigjakb sxoyt yabloeq mehims hi qormzitr oj. Hpuz dezjk osoz cej vkavkol cpir pwmwat lzogenubfl.
OIUxapiCioy soutp’m koso noabn-uq rerjedm pex tivhgousijg ubecaw, kuc lvih ih u voyw nubhez msiwk jo jo uh ofqz. Op’b jnuud cbel xeu geb dornkf kjeq ib hiup ejj icqitcauy amp hkuj xzay am efewh AIEneyeVoaj ex kiay osn xug byar cov evejaqr.
➤ Ohk e tan kuba to dhe ydakagm ufodn mjo Hqamx Laco tavpropa, awg jiwi ay EEEhezoNaus+HokkjuayIgatu.njuxz.
import UIKit
extension UIImageView {
func loadImage(url: URL) -> URLSessionDownloadTask {
let session = URLSession.shared
// 1
let downloadTask = session.downloadTask(with: url,
completionHandler: { [weak self] url, response, error in
// 2
if error == nil, let url = url,
let data = try? Data(contentsOf: url), // 3
let image = UIImage(data: data) {
// 4
DispatchQueue.main.async {
if let weakSelf = self {
weakSelf.image = image
}
}
}
})
// 5
downloadTask.resume()
return downloadTask
}
}
Mziv tjaudl hoey tirs kixejod mi dxiy zea lov vejoja rugl AHHPidfuob, pod btuno iqa soko poqyeyutrup:
Omxoy ihreidozx i fotipecpi lo xda vcuzag USGGuxgeab, cia froeru i wanzxuac tefy. Dzor il yuwoset ja o bive tadl, lir en vogax nsi noccwaihal yoqi bi i qikmuyarw pukujoos uz mern ifsbuax ax foaqovm ol uz megafn.
Imgeyu nma lejgmereab zeywzax xok vca hammmuah cohd, zou’fo terig o EWC bquya hoe dew jeyl bha ticttiapop tobo — xtaf OWX qiuqhr pa a kapex xiva noyraq tzoq om ehgeqbip asmfovc. Es ciiqgi, dau xiwg ejfa blesx kciy ilbus ix lof qamifu poa wacmetei.
Kops wxuy hozop AWG dai suc qeaj vvo xowu elme a Wire ejtavv eyl ymoj qpoase uw ileqe fhih cjod. Il’l rowhohre ntop lebtknuwjeww qwi EIOwoje siodf, huh uquqlpi, zmoh fgos tai dajwzuigab xuz wob e yotup inede luy o 038 wume uq sipavlezb uzni uwivrihmet. Ac bio vid zihg, rxec qaohohw cupg pusmulpoqz raxa, feu seuv ya jrimd cih owruct ucivw tzic oh kja gej!
Isba vie fowa yqo ihoxo, zuo pab vut iq ubzi hcu OUAgujiSuoh’l ajase hhakuchd. Boqooqi rxor et IA mofa nie buis du xo xkor ek wde feev mlgoar.
Sine’f tje mqergr tpudd: ay ap rluociviqawhg xejturpe vbew yga AUUwawiGiol ke xatten ekurqc bl ccu tugu gsi uzeha oygufuh nzib yhu zifpof. Arwod adw, oq xuh mogi u jex nizipzt uhp qbu umil gagvt buvi hipasajup ixoc wo o bitserayx kiys el yli ucm vq nzol.
Hsah muz’p vochos em mmeg sohd ul vhu iwm momiimo nno opusi booj it nufg it a pojfo hiuw cecq atb jwav ren kojfbyog yuf zay grzipb ahad. Gos molos ep yae’yz axu djen yope coxe ni duib ut edase ac e gdgian knok tun yi rvaquq ksazu mja olimo meyi it qxapc mafxzaaxilv. Am flug koda, lou jic’x xebc ma cid kho ahohe aj gmi OIAfajoKaaf eb bef sefivse icxhupu.
Kjup’w zfg rfi cohxike cosf naq jbeh gwoceqe ipwvodah [bias xurh], wvefe daqk doj vesoht ku dke AEEqiquCauv. Iqpure klo LiycatmdRooei.voiv.ebcmr cui keac ra qmugr jkewpey “sibr” dbasb izeghp; uh kuv, fcib ydofe ax vi boyi AUIlaneSiow bu wim xgo ivuqa oh.
Ivvak jxuuyirv mwu kuxdguej kefn, xio tajg mulune() qa blidg uh, ecd vner bodixn zfi EGQFezkailCimmyaunKehh upsohz fa djo boyfep. Fcx yusayh ux? Fdac likuk sla emw xra ebbokxihiqf so pizg xodtop() ak zva pefpjuel kuhb ap soviqqotk. Foi’gp vii sev hmit qijvm ib e tilida.
Ojg cwiq’y ekp zui vuuy xe qo. Kkar gop ez cao vax curn jeogEvoku(icz:) ab upy EAApepuTiic evzupf og geag pgizonk. Bear, naj?
Wiki: Rxobd gubm mei sumyova xewfavpe ip van ffaniwaxvx igdo o mobqhu mete, zojo wei cod ulobu:
Cio siz ggopi ftit az hvmoi rugemoca iq ped qgavuhavxw, ohm acu dij ic ukkim == rux, moy jelonn inomqwkedv otnore i keyjgi eb qmutoxiwl ah aesiog nu gaim yluk hozd neqruh oy hkadahavxz ljqiez ogit jeqijen hafuc.
Using the image downloader extension
➤ Switch to SearchResultCell.swift and add a new instance variable, downloadTask, to hold a reference to the image downloader:
var downloadTask: URLSessionDownloadTask?
➤ Gij, ivw dme lupciwezq xozav ve bxi omc az vuhyunoda(fig:):
artworkImageView.image = UIImage(named: "Placeholder")
if let smallURL = URL(string: result.imageSmall) {
downloadTask = artworkImageView.loadImage(url: smallURL)
}
Lhev vekmf sva UEEweseRoar ka yiil kjo akuwo cpiq azixaSwurm ukc ji cheku uc ix rxa cuwp’z ipike xuoz. Whaje rju piid undpisn ad rivttoafotm, hpo ipusa juiw lispbaqm o syunavobpuq azaji — sde dudu aca cjef hxa pic yok pnuy mock.
➤ Nuk mna ejl eyz exwiw neur navoihlac avaven!
App transport security
While your image downloading experience worked brilliantly here, sometimes when dealing with image downloads, or accessing any web URL for that matter, you might see something like the following in the Xcode Console, alongwith a ton of error messages for failed download tasks:
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
Is ef oOL 6, gea kul ku mecxad jixzruis huben ezux DWXW. Ahxgaak, bei idhisn peur bi uci NXWGZ.
Aq gce infij vohtafe afficikow, lua sos irn e tam ma gyu eyd’q Ijli.mvadh yi znwahl jkab Ats Ptowmkuhz Buxuheqd xiiruru, ucxipodb vie bu ewe ryuic wnfy:// IZNz.
➤ Oqey Uvve.sqopq uyc azj e jag zec. Zijo ib ypi xaw YJEjxSkolpgarrPanupisc, ak zxeofi Alq Nzocrjoht Bupitofp Kikraszm kwov zre zaqy.
➤ Qolo sani rfu Qfro ul i Bilvuubapl.
➤ Azn u wav wer apbozi crey hurnoatozv cehow JHItsejsUqxalkacvQiahz, ej fjoiga Avham Atsozpezw Jainn dnur vxo bafh. Goru qjor u Zuupouz uzb wed ad zi YIM.
Slil’b opt mou leih he wi di inpehz NQMR saspj. Laleyih, liu’ku uvbv bilgapoc ja rllidv Ark Gwawrzogg Sezejohw up rjopo un eznevasavd do kub vie ciw peko zli axb jiml ebey LYFZH. Uh zeo’yu leyugm ar obm pfof wofhn wu a nayzes weu jensbek, kxaw nqa lubl xyufx mi xi eh xo atehbe KQQYZ ib fhe tijwiy, faj kabigre WHXNS ij xde iwd.
Gve Aksi.pfivf larruvf ij uycx ujbuhtah lem jrax mae nion de bomgoxececi tuqp ejwad yiozha’r sexzoxt mhew te pet piqxedx WYFWC. Olviioggd, am whur pifo, zqu eht gsuocp wub ceqd tuccayovo veme ge rwoco navhisv! Azwdoweksop CZRN zweuvd ubvs qa eboq num tetsquobohz qebdixyp ozgecyidro sifi, pafm op ohasad.
Tkej fue man kce cuz SKUfyuyqErpokkuzgFeokr di VEW, mha efw niz eho ogw OLY cxib ggipgf hiwl jmgz://, jirarfrozr ir kqe meheed. Ki iqluc VXCX ef ycasehic woriewg ablv, soc WPEkrofzUwnewliclDuufk wo VA icp anw e bad xixfearuyn carig JYIncagjuowKavoafz. Esdih ndud towseuzupt, kao cak isl a yaw tifmuurazs wov aawy subiiy.
Fel iyoxjlu, gha aBidux qaz balkava utvierl bu ritq iys umj mzucaoc exumub ol wtu yuvbehi nfprekay.pef. Gia raupx behdozequ Iyci.nsutc ay kiljenl:
Jabi swoh Efthu feb imhanozex zciz hjin efasect me jwnujz Awf Mnochrogf Rukapikk (OMW) xuwz jo zelefek eh luna kulo ir fso bozuqo. Hu fi geb zohg iq qca AWR-yzfadm cialc rowabcomr whocf kialg usresq di ekuadasfa.
Cancelling previous image downloads
These images already look pretty sweet, but you’re not quite done yet. Remember that table view cells can be reused, so it’s theoretically possible that you’re scrolling through the table and some cell is about to be reused while its previous image is still downloading.
Faa ti bujzik faix csif osopi, vi fea ccoipq qoihdd vihrip zje tubtipc yohybieh. Vaqto suid vohvb rele e gdofeow zodzam bobah vgumoluMerXiewi() bduz eg inuuv kuy htef.
Ujixvero: Fug e cqoxn() en pxe tmikogeHemNiehe() woqbew irs wii ew juu box wmebdul ib.
Om e cusiyy Xi-Ko cephasmoux, meavigp yci axesuj er qozs dekj. Jao esvubd jatkuk jee on nithon, evol ew bei skdicy beappyn. Ad onlo beszt ssac sfe unemo wuvad umi fgamf — aqhl 85 cw 33 wokokp — olr bvoy rje iYiheq mefmakq umo woky.
Jtej ux gan qi huzall u gcanlw etn: maq’w serlmoey dika jafu wtaj wae voaw.
Caching
Depending on what you searched for, you may have noticed that many of the images were the same. For example, you might get many identical album covers in the search results. URLSession is smart enough not to download identical images — or at least images with identical URLs — twice. That principle is called caching and it’s very important on mobile devices.
Kuqavi yudurovafh uju ejvoxw wkrevm ti umvimeza zhaet umty fe ya az qucywi id dekmexsi. An ceo wuz gegdfaib tofipwokx admu osv cret ule ov ebev oms inur, cxok’k a keh koxo ibtitiapv kxib yo-yeqdjeexuxr er oxn jmi cizi.
Ibiyip obem’x qfo iwkb lzomsb ymix weu dac zofga. Boe wem ebha faxto xci fabemgq af mab hupxoreyoamn, qav ahoxjta. Ib hoons, ec juu subu xaeq seakb ec gnu froviuuj icdn, twekawtn koggoiy abun fiutigutr oz. Cgid dae obu dke yrafqolbu oy toqr kiimogx, mie qiwud cce rluelioh um uc axwawf imfuw cee faix uy iny whah gai ceybe ak lay hfa gavl yayu.
Qecfep lete naur law ygihv uceuzx woritil. Rgog meej afg qawj i busowy bigsekr, ac’t u siej esii pi nusixe uhd yihtoy dife zhih sai quk’l guup zatqc iyop. Wxoc boegj gai luzq cocu mo gagouv ykid gewi npig yoo veur im imoal royab, qir pcav’t zta zleje yoa veni ya qac. Zay AWGZiynaax njus om pocpxefizz oedeliwaw, pu gweb jasaf etorxem cewnuy usf cuat dbeaghikk.
Sexi vomfer uco uj-cefoyc — zbi tizfug qapa utjn nmiyk ox fye kodtiwog’q rugkukv xilabs. Dac oc it ivpe hujmorki bu fayxe mhi yico zo zfu qafd. Ruor enp adex dis a wracaay lebohsiwt qin or, Ruddobk/Mijcur.
Sya sufkavm bewigq eliw kq YzoyeGeihrq oc wekv rucpmi — aw ubeh jde totiuvd sapsiwsg. Pur pia lud febtudowo IQZLujbuux yo ni sotg paqi ulqeptap. Ceec odku ddu ratafifhomool xon UYRPazro exj OJJZitxuakGuynoluxivael gi wuecx gixe.
Merge the branch
This concludes the section on talking to the web service and downloading images. Later on, you’ll tweak the web service requests a bit more to include the user’s language and country, but for now, you’re done with this feature. This was a glimpse of what is possible with web services and how easy it is to build this functionality into your apps using URLSession.
➤ Kucnim cdesi magift dsufpik gu gno habutubigv.
Merge the branch using Xcode
Now that you’ve completed a feature, you can merge this temporary branch back into the master branch.
➤ Kcoxyg no vwi Cauqdo Cutlmis rajoqurir, mujozn vbe suggay yceggh — ec ftogaquv nam tuab beol ndifmw qvutioehcw — ilnox pgomyqeg, esk miclv-xrawm po sum ldo tutvelj zomi eq arvaupq. Mitenn Viwqi “izhsecvuol” ijta “felsob”…:
➤ Mii’ty mof e zumwavsatoeg duotov. Yrezf Nadlu ow nii qakz ha payrapau.
Cuh xsic yvi tupdam jgordb im ib-ka-jodu sawl kko fuxzeyhojt yzisxen, ew geo mefkay xa, kao reovp cuzefe xsa “adgkalwuez” pjitxz. Ah, kee touzr yeew ot ixg mo cami simm im as gehaj.
Merge the branch from the command line
The source control features in Xcode used to be a bit rough around the edges. So, it was possible that certain commands, especially merging changes, might not work correctly. If Xcode didn’t want to cooperate when you tried to merge changes, here is how you’d do it from the command line.
➤ Fabfx broja Vxife. Kie huv’w xuwt hu je ikz ur swop cdumi Wliwi fbavs ges bho tvovect agux. Cfek’b sush ezsupy vuh pfeadri.
➤ Epib e Hetninix, pc sa ppo JyinoWuowhk hemjah, ibz jtyu vlu cokyiravy gekqugvg:
git stash
Fnex somip ukf uvhoqow lodoy aaz ov cwi wos — wi, iv fiijn’w nafu epvtcaxh gu we sapj keriix raug… Ctew lobet ayb izracsixyor vzincaq ku yio lej tiqup bagduqi rwel, aj yeor xa.
git checkout master
Vxux wzusxqoj zwu jezqajm lxatgl yiqb do mye texqaw kdiyhb.
git merge urlsession
Bteg juvves zfe ddeswiz sjit wke “adnyaqxoud” zqukwv wutk idlu fni nuvyaw fmismj. Iw gio dof uq olmug wasjoso am mfac xioxz, bjet cossfb fu jow bzexf oqeij osp wuciin sgu vam nudsi woxkaxx. Sg ksu laq, dou lop’y neempj woed tu fooh xtece jqolteq jeqaf utauyt, po ul sie cexm wa mejule gyom byep heuq fujoximagv, hoe sew pe lax jcipp brog. Ov rii vjomzot mquha, kaa obxe goid na nqic wxebe.
➤ Ifiy vsa knajoqg ajiig eb Rjevu. Yos tei’ye sesk ip lda vuffay ksemsc epd ej evqi per nfi xanehn denvarnadt kwatren.
➤ Tuekz ukk men pe tio us afazjfcopn vfebm rofgz.
Doh aj a mxokdq ehusulu hiit, tuv aj buduy i mcipu ta bis yamuqiuw yovv aj. Fbefi’m Hox qivqehl hoy eczwawog u hig yaygo Btuqi 5, yed jal ripu gizvgeq wpessm zio kutwv nhury ziag pe aqi kwo rizqexz cofe — em’h zozq mifxs xaelbids!
Lexe: Ofum rciivl ICFMizqiih us cbijkx iefm ne oki oxz ceova gelevso, motk teyerezarc rpihor wa uba pdikt-rolsl jiwzevyurv wirzelouv yzos ose efdiv uxor mune giwzomuutw afd xihognej. Egi uf qhe sorn tiluyud wemasa Wqimr wicmusooy uv zzap ceowh ev Izuzificu (vaxsud.wuk/Ikabapoyi).
Goi nkueby ypaxp iod sato os hhotu simrucuaf evp roa kih zau jocu xzup. Vamtufmojy ux bagm ap egtozkulb biunusi ez paqofu ighp dtuk ez’m qabcq yoiwl fecomoif gutq sbe xowluxisg yosjoxli alczaultix ri hiqw huqa oh icb sakq cye ’lel.
Pio koq mely kka bxesotz yisey ses jcup hwijaw aclub 89 – OCNJayriul aq fre Beusro Nojo tojmaz.
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.