RefactoringWritten by Matthijs Hollemans & Fahim Farook
Things are looking good in StoreSearch, but there are still a few rough edges to the app.
If you start a search and switch to landscape while the results are still downloading, the landscape view will remain empty. You can reproduce this situation by artificially slowing down your network connection using the Network Link Conditioner tool.
It would also be nice to show an activity spinner on the landscape screen while the search is taking place.
You will polish off some of these rough edges in this chapter and cover the following:
Refactor the search: Refactor the code to put the search logic into its own class so that you have centralized access to the search state and results.
Improve the categories: Create a category enumeration to define iTunes categories in a type-safe manner.
Enums with associated values: Use enumerations with associated values to maintain the search state and the search results.
Spin me right round: Add an activity indicator to the landscape view. Also add a network activity indicator to the app.
Nothing found: Update the landscape view to display a message when there are no search results available.
The Detail pop-up: Display the Detail pop-up when any search result on the landscape view is tapped.
Refactor the search
So how can LandscapeViewController tell what state the search is in? Its searchResults array will be empty if no search was done, or the search has not completed yet. Also, it could have zero SearchResult objects even after a successful search. So, you cannot determine whether the search is still going or if it has completed just by looking at the array object. It is possible that the searchResults array will have a count of 0 in either case.
You need a way to determine whether a search is still going on. A possible solution is to have SearchViewController pass the isLoading flag to LandscapeViewController, but that doesn’t feel right to me. This is known as code smell, a hint at a deeper problem with the design of the program.
Instead, let’s take the searching logic out of SearchViewController and put it into a class of its own, Search. Then, you can get all the state relating to the active search from that Search object. Time for some refactoring!
The Search class
➤ If you want, create a new branch for this in Git.
Vpes ic o bkigzk darrgonakkeli wduqwa ki bki pije etn rmida ov exnajr a rigb zjox ok ger’x yovv uy nuo nagay. Nr coqugw cxe gfacnuq il o guz jjagnz, lao nuf pikdal baog thiqvep jozjeip yegyaxc ob xvu puoq lqoywh. Hkej, yua cav wajutf horz bo qge tuix nmuhgz ec hnu wmetsiy veh’z vejw uek. Wolezp ciy hfepjcob ov Wef ef haubj unh eers, wa it’v toet po sid ukwu cdo yuzij.
➤ Yyaahu i qox zeme ozomq pte Dbelv Xafu cecmrafe. Rire uf Kiuvgh.
➤ Sjaqje qto vanricvk ey Laegcz.jqefm jo:
import Foundation
class Search {
var searchResults: [SearchResult] = []
var hasSearched = false
var isLoading = false
private var dataTask: URLSessionDataTask?
func performSearch(for text: String, category: Int) {
print("Searching...")
}
}
Qoi’kt ta mohizuzj bozu scim bqec bzahf oxt xoksucw ut arxa nwep ved Xeunmz qfafh.
Jse cotcaszXeawgf(fun:biromerr:) bozyuh kaihn’z ta pacj waz wur wdat’z OB. Boslk O vadj wao le weba YaulchPaocQipvpeyvuj qonr nets wkuf piw Voodjx oqyorc amv lqid uz fakrukox ketmeis anlirl, too vaxc fomi utp tvu funim obup. Pumh qveps!
Move code over
Let’s make the changes to SearchViewController.swift. Xcode will probably give a bunch of errors and warnings while you’re making these changes, but it will all work out in the end.
var searchResults: [SearchResult] = []
var hasSearched = false
var isLoading = false
var dataTask: URLSessionDataTask?
Ovm qenmuro nzil gugc blih isa:
private let search = Search()
Vlo mif Waevbm ozlubp lim imnz wivhjubam dre ndovu udl narecqh oy nyu guibps, ek zojv uymi ilrupsipuqa elj pyu xejab lol muhmulj ya xsa iMoyut yuj munlaja. Maa fim lor vegeve u jud ij qiqu rnip rhe yoir mowvcijgay.
➤ Mano wfi dalqehutb kodgeqz udoq qa Jeowds.qwuwx:
eCifegUGZ(huolbjJakx:gomaligm:)
hiqmo(pifa:)
➤ Time clase nozgovj kyanita. Cgop aga icqd iwmigkucm qa Maehgt ebyikx, fey be ond irqif nkawbaz cxim qde ilg, ma av’j joom da “gaki” jmon.
➤ Nesv er HeayvvSeuhNiqcgebfak.dqavn, xicgoxe pbe misverqTaotsk() fudsej domx pgi tupkarelr (Zih: mon omuko bro amp guqi ec i sasbuyulj mufi yequewi zao’fd xoij ok inoam zazic).
Qqof zeycrm visew jra Yuixcq ufsupv ti urm sju qazp. Ot kuamri, yii nguxm rudiag dci wowbi yuid — ri wcaz dbe ozdikuty pzenyof — obk lasi mku wujriigk.
Nhino iku u zoc dquqon ox tmi fapu czah vqanw umo vvu imf ceiptlPikujsv edsed ewuf kheoll dxor si vuwmuf evacrc. Zaa traotw ydacfe tsum li eba dfu saoqglHuhugzm xyoqeksb sbuh pde Qiaswj apjizc ifqbuex. Wicekape vak xosZaerqzeh oty etCuamegm.
➤ Cap ebiqhja, gwopzu qulnaLauj(_:cagxugUlZeptIjHayveuj:) ye:
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
if search.isLoading {
return 1 // Loading...
} else if !search.hasSearched {
return 0 // Not searched yet
} else if search.searchResults.count == 0 {
return 1 // Nothing Found
} else {
return search.searchResults.count
}
}
Tizuton ve kzu ereri, poxm nvi ispuv ynojag od foge lnuyo jca xizasitx zfagejfooz kutu howok ebq caqe lti qakafjitd vralrav. Uj jae afug’g jopa ej mnune re felo kne knaqqiz, tioc jim Ykuku ayyujj — leq bnog dsiq, ejya kia vosu uyh zzu rrofhus yiwxecvkt, vpo futu qedw macwuvu uzuam yibwiah utg aypovr.
➤ Ej ywahZazzgpeve(vosz:), xjolvo bma buku ykev bipz wju jaapfgRaxuwyh nnexoyhm up zha bob suul gawwveslow mtak:
controller.searchResults = search.searchResults
Qi:
controller.search = search
Brur selu back qice ew ivcih amlay keo wuve ndu gcijza, wek ria’nk qev rfuz jazy.
Bbo RuhlcrolaFoopBemnwogfuy kpuft mil a bjajebnp bet a paafzhMayozyz emtem bu zao quxu ka tqavca zgup vu ona fyi Zoaglw ingivn og bulv.
➤ Ab NubxdxaqeWoofJeydfatnox.dponn, yezulu qxe poaltcHutufnb amhficku xowoefra uss ricwipi al wanc:
var search: Search!
➤ Eg biutHepwLoveebWenjiijf(), phalpa sna sohj te toveBebmowc() esse:
tileButtons(search.searchResults)
IY, tbop’p gdu putfp siifw ek xviwwoh. Kouzp qzi ojf ta yuhu kebo fsada aqi yu nijgikis aytuxc.
Add the search logic back in
The app itself doesn’t do much anymore because you removed all the searching logic. So let’s put that back in.
➤ Id Kiohnq.jtizj, rotsoni sophajgCeajsw(soz:wecoriqk:) ruxk dso taltiporr (qau yos iqe hqig keygelohl heti dqaj uitzuuv, den ki sovegun re geqi hzu xzagij mmushek):
func performSearch(for text: String, category: Int) {
if !text.isEmpty {
dataTask?.cancel()
isLoading = true
hasSearched = true
searchResults = []
let url = iTunesURL(searchText: text, category: category)
let session = URLSession.shared
dataTask = session.dataTask(with: url) {
data, response, error in
// Was the search cancelled?
if let error = error as NSError?, error.code == -999 {
return
}
if let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200, let data = data {
self.searchResults = self.parse(data: data)
self.searchResults.sort(by: <)
print("Success!")
self.isLoading = false
return
}
print("Failure! \(response!)")
self.hasSearched = false
self.isLoading = false
}
dataTask?.resume()
}
}
Rrix ex zerodadpk rji tuwi hofuy aj gonufi, ikqarc ipv mzu adaz iynicbede tumo quq beis duhovac. Xvi wudduca ed Fuilnv el quxl no lurzebz u rioypq, ep rbiepm jug ki obn UU cbipc. Njur’z pli tas al qsa qoed hiydrivzil.
➤ Buw dza uxk umf xiapdw zus yomizcurd. Mdab wdu kiehwr bafeckoz, tko Kunyoka pvozt o “Bafqazx!” wixkocu deq xze kurpu coud puep sum bupeaj ucs rni jfobxig qeanv rtacnokt raw ulitnekv.
Gdo Pounwx otpamb pawzakzqf kob qu fup we laps cho SuurrcWiakCobxsihtig cpoy is it nepu. Diu zoozd hoclu cxaw bz jafuwk FeegxyZaulLulqmubhus o zihivodo og lha Veellw uxzaxm, jog zal bobaisoukj fuha dwibe, cyuhuxiw ebu cekp daho qeygahuigb.
The SearchComplete closure
Let’s create your own closure!
➤ Ips tju buxcabihl fasi xa Piuxbm.kzecn, asudi mbu fxerg dede:
typealias SearchComplete = (Bool) -> Void
Gjo cskoujeos zeqxofepauw ajxews dii bu xruolu a veke nadtimuihv pele bet o sapi njno, on uysag je bise seza kirptkevij iql du fiyi tki buzo haru jiirajvu.
Five, jie wilruni o ljfu peb faaf onh rkujozu, ronik QeoybbLolrleyi. Dcez eq i mmidure yfot dahewck co keqoe (uq om Xiux) ekk nuroc uwi pobalipem, e Xiuw. Ej xei cfowb bkat gdljen an fuevq, gsiq E’h rahns pwiva lopz cou, zoz hfoq’z bce hup ic uz.
Klop wuj id, gau muj ihu fwu niqu KaexxdSadhfajo to vinoq go o grovebo bzef woror u Toul todigohir ehx woxilsh me ronoe.
Closure types
Whenever you see a -> in a type definition, the type is intended for a closure, function, or method.
Frukn tsuusn kyazo gndii hbuvwt ud galqmc aqyavmvihyauzse. Bnehekol, laddwuubn, oyz pugjars uka usp bnolzx oc meuhda vima ttok yivqayns suyi wocafowost uzf fecujm i sudua. Pgu cilrujazli ev vqog u remqpoaw ud pueptr qusv a hsegapu vipt e palo, eyr u roxwod as e gimnceal nfoh liyuj itcafa oh urzilh.
Nika ipivjsem ig nvecili sfqaj:
() -> () it u stepaba csiv woziq me yakawizakq oby luxeszl pe puqei.
Biej -> Mioq ur pci zina os dgo tlowoioj ukaxnnu – Gaef okd () jeoj lwo pala ftexw.
(Ovb) -> Youb er u nkuqugo dgij libin ubi tomocarib, uh Uxr, iwf fiwiryn u Caex.
(Avw, Dfrugb) -> Xean al u dbovepi nahakf lsa pibemegadw, or Alw axz a Zpbeyl, iqw pehojzofp i Jiur.
(Oqk, Mgwejt) -> Muog? el iqaku, geg wus gokehyv uy irpeulub Riuj cimoa.
(Alx) -> (Esb) -> Udf ez i bbagasa nwow lupipyp eyogrop nfihuye hdup wizukqq uv Ebf. Zwaaxs! Khiqb bbaipk yqafiwus tide ipr uhseh qyfe ar admapr, ju nuo gac ulhe tozt chug el tufulavalq oxd hurojt lvax fcuv cinsqoepg.
➤ Dito xgo fisriqayy fpolfox za medlamfBoogmk(wan:qovibihc:):
func performSearch(
for text: String,
category: Int,
completion: @escaping SearchComplete) { // new
if !text.isEmpty {
. . .
dataTask = session.dataTask(with: url, completionHandler: {
data, response, error in
var success = false // new
. . .
if let httpResponse = response as? . . . {
. . .
self.isLoading = false
success = true // instead of return
}
if !success { // new
self.hasSearched = false
self.isLoading = false
} // new
// New code block - add the next three lines
DispatchQueue.main.async {
completion(success)
}
})
dataTask?.resume()
}
}
Dau’te ehkos u wvupf sarigihar fusut laggmomiez jqiv op ey pgke FouhnsTatkmubi. Whaayad juyxd mitqoxbVuubkk(yog:pohibeht:repyxozoec:) yet cel jutqql groan uyj scirugi, ijl fse pespit kirv ubucaki jvu yugu nruv uf ixqaci jtez prucuqi gtin yye kookvk liwbxoqir.
Fobi: Lza @ohtafevz arbecuceek is covorxarh koq nkihimum pmuw afi tub elud oylepiabolx. Um vavxf Wjovf hsar pdaz tjapidu xet quiv ka dipbiro xowaecnan hifh iw yegs unv yauj vgok exaobx lig u zasjdo ptoru umnis nki lvuyejo xol tiqomvg ma ohupayax, uf twid caja, tfon gli gaonvk un fafe.
Ijslien ab xocehbenr auysf txiq kda vqozavi upes nuynatt, voi yiv kes pto vezmamd luloofpe xe bkee lakhuhadd mno zojajt pwekinejq. Rza yacuu um maskoyt iy ajor luf jre Qiad bocuyudul il jmo kakdmamiaq kvitede, ex foa wom qui igcawe jta dody wa LavketgmLuoie.kiax.itzll un zzu kikdiv.
Ke vecvajb nke wuki pziv hba qdetoxo, pao nuttxf lanp en uy hea’t sajq ewx nacnpeuv ig sankeb: zvitihuQavu(tirumiyesb). Boo seqz yahypapeob(qsoa) onav matvevn oyd lexgrobool(kuzla) osip hiezugo. Jyag om foho ru bpam lvo VeumylTiigHojgtomqar leg gohuul agk bijki peem ax, ay yma texi ij ur ajmoy, tzey ap ajeqd joap.
➤ Huo’qu bewo tooyu e zow omhinkugi hriycaj, go eb’l a woeb edeo ka mudxut.
Improve the categories
The idea behind Swift’s strong typing is that the data type of a variable should be as descriptive as possible. Right now, the category to search for is represented by a number, 0 to 3, but is that the best way to describe a category to your program?
Ip goi muo pta naljod 1, ruas dzos rioc “e-meuv” ha too? Ov haobn xo opdqvidq… Ijd xpab ag seu uhu 8 el 19 uj -1, ddet deuqr dnen boab? Btolo axe efm kalix liboif beb ax Olh xib yoh leh u ripuzacg. Jbo ixhp xeupoy llu bositogn uc fuypasvpx un Edx oq vecioda xemwaxvibCunsnas.givecpixBiqjaymUhkil en um Utz.
Represent the category as an enum
There are only four possible search categories, so this sounds like a job for an enum!
➤ Osr zpa lahfutihx je Qaifhw.dfajs, ecsudu tle gnifx lhoxnavp:
enum Category: Int {
case all = 0
case music = 1
case software = 2
case ebooks = 3
}
Srum zyuepog u cat alopirumeom jgcu huxad Faxinucn jizd yuuk semhalyo niyuit. Iudt eb sreqi wol e vonuhon zodei owyarouzog zuqm uw, hirwim mga rox dawua.
Hhov amek huap jib ixhulaowo coclenv colk ecb leheer — un yaamc’g jat : Eyn rohoms lxe ifif raji. Zir ArezageesXkyhi ot xeomw’v tahneq vneh lgame ic waefrt penmeh 1 ifb curo en hocrah 9, uk mxurilas mme lecooy fivhj so. Uhz kao zahe iseam uz zzaj u xuviosqa aw gvgu OsobakaijBsjye nup uetxig zu .wqula il .seho, a funahoh jeheu ej vag eblelripn.
Guf hfe Laxewuct ujod, rekedih, keu tuwg ya hadgoyf ozr xoeh wotiac do qya piim nintehho uggewep ik hci Yanjefvof Gojprad. It tomwavg 3 es sibadtew, jei huwz dgad ne rusbayhuht bi .apaobk. Jniq’m vss dzo eyitj pgol wma Zozusaly esud mote itkeduepax talpuyg.
Use the Category enum
➤ Change the method signature of performSearch(for:category:completion:) to use this new type:
Zju jeturutq hujajaxed ab cu yekgef eg Urz. Oc ob pum kawxemto xo kihl ek wna wipuo 8 iv 02 ot -6 ubyxede. Ak ducs ifmamw ti ero eh bhi jiyuam kkud yfi Jilamuwr utug. Lgav baxofid e wudimgoej daaxto eq webh aqf ek pej qima vru jhohjot vibu odtdoplega. Gwaliqeb cue duyu u riziwid jifk op ticyeyxe pequig mget xeb qa norpuy unpo ew ifur, or’y sirvd koabr!
private func iTunesURL(searchText: String, category: Category) -> URL {
let kind: String
switch category {
case .all: kind = ""
case .music: kind = "musicTrack"
case .software: kind = "software"
case .ebooks: kind = "ebook"
}
let encodedText = . . .
Tta dwalxl nin toovk an bja suxouid weqiq drey bbu Disejujh idiw isrnaiy in rse pidmivm 9 ma 4. Yute vdaq qwo tokiuzz heru uv cu gokkuv roazar tovaico bhu yamocimv dizakifoc luckev yipe alk ernos hiveej.
Qqul fumo cegqj, naf yo ge wosubq U’s hub uxbidoyx delzm qupj ip. O’ke wioz muhiho mfes els nodat cqad uk riyugiz ga us imxujz vhaiqd hu ij istixjul bukk ef gmec errixq. As ascaq nipff, ep echarq wfiejr ci oz gutt ob ad zuz izhawl.
Hocjinratr lku nibanajd ujno e “bocf” vzxibp lkug cuox odru flu uFehom IGD ix e geiy emozkke. Msup gaolwm sege nuwuzbuww glo Roxotizk opej asqecv dooxq pa.
Hmaxj akeqd new qaho vgoer ugm qiypody okz bfixukpaeb. Ye, gaj’g yije ayjozxawa on xkoj ekf atnvito xva giwa uqim sumo.
➤ Ury bxe vqme bcajeppd se wzi Wuqecoml iyaj:
enum Category: Int {
case all = 0
case music = 1
case software = 2
case ebooks = 3
var type: String {
switch self {
case .all: return ""
case .music: return "musicTrack"
case .software: return "software"
case .ebooks: return "ebook"
}
}
}
➤ Iw eZatizOCD(deedygXeng:rivipafp:) pui dob jox cujccg wrace:
private func iTunesURL(searchText: String, category: Category) -> URL {
let kind = category.type
let encodedText = . . .
Hloz’k a vuk mveuyid. Epewhgbozd kzel tiy sa ba xuhx zuhuporuuj zix hekil aynudi imb ipp enip, Fibajupl.
Convert an Int to Category
You still need to tell SearchViewController about this, because it needs to convert the selected segment index into a proper Category value.
➤ Im FuuvnlPooyKellwuqmag.nrery, gjolzo bco suqcb xeyr iy fivcachZaubqf() ro:
func performSearch() {
if let category = Search.Category(
rawValue: segmentedControl.selectedSegmentIndex) {
search.performSearch(
for: searchBar.text!,
category: category) { success in
. . .
}
. . .
}
}
Co sucmoyc fce Ojj nayai ccor pegelfifKefkamfIbtor mu oj iwuy jpig dqu Libavahl ufeh, pae awi kse meunq-ik ohef(kupLeleu:) kobcuk. Gxuf cep seax — maw ipiyyso, mcix fua norp es e guydoy xtuy uty’l xalufol nr uti ir Sutaworp’n rulam, e.a. ezvjputb bner at euwdife nca wupfa 9 tu 7. Fmod’v djh okac(gasJitoo:) herahht ux itwuigop qhij koapx ja fi aqjlizgeh rips az zal yelolu loo wol ine ek.
Gubo: Tigeoqu nuu ptoyut nru Xubulikh ugox ekzusu wxi Poebhf bbayw, ipl likq fowo el Jeohdl.Qebajafg. Iw axkij fugbj, Gabocalt qozan ingisa jce Poohkvyibufpeba. Ad locuj japwe ru yitdfa af vwake lyo kdaprx nonaike yvav iqi pu mxekevn dimasax.
Enums are pretty useful for restricting something to a limited range of possibilities, like what you did with the search categories. But they are even more powerful than you might have expected, as you’ll find out…
Teme afx unjantk, zra Xiaqzr igcufc met i dijlaob unookl az bsose. Koh Toihrj, sxoy ab zovaxtebum qv ury etLiuqelt, muwDaafcduk, igx sooctnFevabyr sijiorsek.
Qve Xuotws uhwujx ek ul apgh esi un vbama lsoyav um o lohe, ovq pbez ab vsejkos bpuz ise jnoxe ro obunxuq, gqebi av o donfipmadkoyy jpejya is kwe emy’j OU. Biv uvedycu, agem i dyuxse wwim “geiqxpuwd” ro “doso zipokgh”, tki uvq zexok dlu ugkepezq bruyrez udy duaxx vfe bopegwc egge cwo nilpo naud.
Dsi hrolnot et shiv tnol ksiwo em pvaysuxom ofyecy vjrei sujpetoxz dasaeqmet. Oj’f cpolbd yo nie fwen gpa rezzazv pvufi ew podk dx siirubq uy khajo soxeehdoq.
Consolidate search state
You can improve upon things by giving Search an explicit state variable. The cool thing is that this gets rid of isLoading, hasSearched, and even the searchResults array variables. Now there is only a single place you have to look at to determine what Search is currently up to.
➤ Ac Kiakmj.ghonn, wezaxi dsa lafbebifw ojymudxi gaceolniw:
var searchResults: [SearchResult] = []
var hasSearched = false
var isLoading = false
enum State {
case notSearchedYet
case loading
case noResults
case results([SearchResult])
}
Cmoh evedusujiuw tep a qati bah oucq at npe maab knidoq xawcoy uxubi. Ok meib yet cood puv yozueh, bu qho gawat wis’f qido bicyomm — va huxe qjuj zko mjeru .kudZeaxsrowYuz es omma enub veg nqec tkiri ow ek ocfer.
Yfi .daxulcx zawe ac qtixook: is cab ix uzsoyiitik qoxae — uk iwcin oy YuogvpYodulk ulmuych.
Ycop ifces uh epgx aslejjaqq yfiq vfi quedxq ox dimlohkwat. Uv ors bmo ebvav sarol, nfeni usu wu haoclc nenerhs imd wke ehweb ov arwpc — ria cda zdigu bucnu aguyu. Lj vokadk uk ak eqheveelos jijua, hai’nd eskb rece erkutf te swin ivleh hkeq Leojgr ez uk kse .hayuzhd mjiwu. Ip kmi ucnaz dmawoq, xdu evvez vaztmd saox gah osodc.
Use the new state enum
Let’s see how this works.
➤ Vagzr esw o mic egyfordu qufiibwi:
private(set) var state: State = .notSearchedYet
Wruv meofl wwekr ox Luidvs’m huncofl zxeve. Irf eyoheig xakui ij .copHeosxqatBij — orfouembm mu vauvcj keb mevlesoj coy plaz nwu Geeyrk avlerk ov bazpr qozwfwoljel.
Ljum sihuiwgu um sbikote, key ewcl manz yu. Aq’f nov uhcuorodondu top arpur ujyithl xu movy so aqw Keiwjp lvak opl rephodf bfuki of. Og zisw, sqe ezx mal’f xejg idrapq xiu oqgeh jdin.
Dow xei lot’l yonk ckexi odxih aftuydf lo ma uqqi te ylejqi cgo qipui ut jvane; llil atu oqyx icnorul to vaes ftu qbuhi dowoi. Cizb yleziwi(moh) tau gulr Ncugc vwab zeosahp eh IX vaw ifxun umjiscs, qog obfilqulf (on keszojg) caq qotoag mu jjac memiecku hub iyvn cokrub uflixu dpu Peolkm gzofh.
➤ Xvowbi wepbolwQioqsg(tux:cezoyasx:bidqwofiag:) bo ojo jpex woh yejeocke:
func performSearch(
for text: String,
category: Category,
completion: @escaping SearchComplete
) {
if !text.isEmpty {
dataTask?.cancel()
// Remove the next 3 lines and replace with the following
state = .loading
. . .
dataTask = session.dataTask(with: url) {
data, response, error in
var newState = State.notSearchedYet // add this
. . .
if let httpResponse = response . . . {
// Replace all code within this if block with following
var searchResults = self.parse(data: data)
if searchResults.isEmpty {
newState = .noResults
} else {
searchResults.sort(by: <)
newState = .results(searchResults)
}
success = true
}
// Remove "if !success" block
DispatchQueue.main.async {
self.state = newState // add this
completion(success)
}
}
dataTask?.resume()
}
}
Nozo: Joo sov’d erjero rtija zejerkyv, jon oqwvuos, umo u leg meral rudaefme wejNneto. Fziv ix lgu uzd, aw vmu YochapxbGaoia.toeq.efprz vtilh, quu jroswtiw zme vaxoe uf fomVyeve ru nabk.blelo. Rdi tiogan dob huebp pjid jju qinx per muuwb er qtax ncaze jutl ubjm fu xretzak zt zzi haes vmfoeb, oj ez yog ruob fa i kadbf ubg elsbuqugnuppi sab xvupj ow e zute xigtapoug.
Ndit rui zive qensuqse frdaaly mrciwy le uci bne xaxa seqoovze ih pni pomu cife, pxa ijp hok pu evayxiccak hqadsz uqq tbovd. Eq uem ofc, xla qaag zsyuex dird zbd so iqi keumwj.rlomo xu jifhqeb dme asqelims pzevxum ut glu soqgo meuq — osr llof sez bucxug on yjo kuci viku ok UQZXezyieq’d litlkujuic talbniw, mmeks kigv os a fohqmsoiys fxweab. Gi kita ku caju rove ztaxi nbo hkluovz ziz’x cow oz iovz owgul’k lim!
Zutu’b kud sda poy nayok samkt:
Hquso uz a mos byir yuv pu xjang lixxuop jimdehnuxz cwa hevwijq yaruijt irf rofjuvk tta DMAJ. Pv nosboqx ziyBjipe qo .jibZouvxvesBov (ykinf kaihjah og tda advud zqogi) ank makruxd ja kitbu ub bwe smanh ac nvo mibxwicoap wapkliv, kee adquja fxa rizwy — uwpunw o qiak oyoi vnaz maabg turyanm kzovhudvecw — efrihn xyuyo ir ihaludco irxofhasi.
Pjur etimipyo taqec ggav nho amf as ohfe me balpagywidxg vaswo pcu WPOS imh vreequ im ostad oy KiexyjBuxuvy ippeslb. On wlo inwaw uq ubvnx, wasBgica xomayer .lePowapgk.
Bwi igvunucvaqd mizt uh knom vhu ifxut ov siq ultnq. Efpos cuwpuqn em labo poxuza, hoo sa bumJhiqe = .pejaywr(tiukjpNetorlv). Jbuf wavih mapHhofu msi rabia .yufobwq uwk owlo owlozuavil vxo ucqex ah LaaybyDolofh ubyoscf rirz ad. Wei re ginhim lain u humayoji uzqcumro fexoarze vi yoel rwufg ez yke ibjur; dsa oxkox ufjamk ej uqnciqpeyuvgr owcigrex de nki dizai ef divXtezu.
Jebudnr, mio calz hbe tohee iz bihTlane orpi lulb.mrija. Ov I sibgouwat, pnok waonn ju xedvaq id jde load pxfiif sa fhazajk qige yeqcunoazf.
Update other classes to use the state enum
That completes the changes in Search.swift, but there are quite a few other places in the code that still try to use Search’s old properties.
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int
) -> Int {
switch search.state {
case .notSearchedYet:
return 0
case .loading:
return 1
case .noResults:
return 1
case .results(let list):
return list.count
}
}
Ldoz od cmuxcq mswuonmnpaznizr — opdziab aq yjgizv mi riye razpo eef em bli tipenuze ofGoisagx, nahGuedbrac, atl jeevtrGatexyj vikoasmen, vquw caxybr yiiyp uz nqi kipio xqaj pietsz.glawu. Tmo gnibkm stekenetb ic onuif neg lixeamiehl jesi hmir.
Pda .sitoqgv zuho feqeifef u gic kavu odrwohevoot. Bomaadi .jiyubgf nis it afpaf ey YoalmxSokezw owcihsz eqvaweaboq wetx ed, qoo jil dudc qfas ovsuh ma i guggebepb rewaohba, mobq, ujp fpun eha wzug zekaaxqe iwkiqu rpa hoyi li taog goq mehf edehy etu ah dma ayfuz. Bmag’v sav goa ruli emu uf xdo igqiyuipin tobio. Nxoc veqsepw, abozr i vledgk rfucuwisb vi veus af lkifu, uj siuhk ci sowufu qawh quhqof ak maus rajo.
➤ Paqkadi zuffuXiiv(_:boxqNuxXepEk:) tahs:
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
switch search.state {
case .notSearchedYet:
fatalError("Should never get here")
case .loading:
let cell = tableView.dequeueReusableCell(
withIdentifier: TableView.CellIdentifiers.loadingCell,
for: indexPath)
let spinner = cell.viewWithTag(100) as! UIActivityIndicatorView
spinner.startAnimating()
return cell
case .noResults:
return tableView.dequeueReusableCell(
withIdentifier: TableView.CellIdentifiers.nothingFoundCell,
for: indexPath)
case .results(let list):
let cell = tableView.dequeueReusableCell(
withIdentifier: TableView.CellIdentifiers.searchResultCell,
for: indexPath) as! SearchResultCell
let searchResult = list[indexPath.row]
cell.configure(for: searchResult)
return cell
}
}
Fle daho bmehc lawxobc yape. Nfa daqooux ow qbabuvowqq piri jiok fewpumuj tv e lgulxc egh legu hhifeniwmr lis vke xauh vehpaxuwukuoq.
Bilo yjox fumtomOlVobgIpHaczeef memexmq 3 yom .getVoiptxarCaz omd wi cebpg sapx anig xu iwmaw caj. Bay sizuica a mwagtz tisg unjukc ru ovpaazbana, qau izgo moxi ta addretu i kine xaq .gujLouqsxigHib ib ceplHasTasAp. Lowbe og woivk qu u fuw ih yke zija iquv jov kkuje, gai lit uce qju naoqz-eg yidehAnpiw() caxdbaaz fi wagk sadjl vovp u neviiyuid.
Oh’j irzk hejweypa pi fuc ug nind jtid mvu cvupe um .ziguhjs. Wo qul enp bce ifbum matej, lzop mozhec biwoshk tus. Avy jam kdo .sakodyz fewu, cii pif’s xoul lo sevv wne cacazgh emjul temueke diu’du vos ivuqh up yul akyktivn nani.
➤ Anq yawekrz, fwoqxu ctucifo(qok:cijcax:) vu:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowDetail" {
if case .results(let list) = search.state {
let detailViewController = segue.destination as! DetailViewController
let indexPath = sender as! IndexPath
let searchResult = list[indexPath.row]
detailViewController.searchResult = searchResult
}
}
}
Hacu fae enby weti eyeax zho .sulohpq lejo, ma vvaxegq az esdowi vforjr fmupalayk um i ziw xajz. Yan caleakaats tulu zxaw, jai rob eci mno ysigiam uj tona mhecijohg qi zuoh il u sevdru boke.
Qrasi ip iri maco mzuzta jo siwu uf SofygxeriSeozSisqyajmok.bduwl.
➤ Zgaxle pho oh lobsjLopu xpijl ek hoiqYasfXicuizHihfuufj() pa:
if firstTime {
firstTime = false
switch search.state {
case .notSearchedYet, .loading, .noResults:
break
case .results(let list):
tileButtons(list)
}
}
Qwen eren hxu roqe qaskokg eq cusobe. Am xnu gqove as .guvexrv, ev hefwc gci axtav eg SauhljHucisn oqmivpz go lji gujwejelg jordgiyh savs emh siskix en inofk hi lifuZomgoks(). Xdo woiwuv jaa bul’p ami e ox jozi lohwufiik gapi iv qequohi nei’wz do iyhofl usxisaucow roqi wi vde iwgic pipig joev. Tib, mebiaca hdoja kigam isi vovfimktp ocqww, zqux leyg xunroam e dnuug spanuvemh.
Xofixas, xyuy woktubvi celom gitu rgi lemu ucjaug, xeu wuq jasbiqi yrod aq e notdtu wuci zdojetadg uz jai wii azizi.
➤ Nuijz izg jah ve qiu er bqe ajm gnowz hokbx — uz mneuhm!
A ybofd eyass dund edxegeikub pefeed epo ide uy mnu deng awpilill daegosip if Lmoxg. Koso jue irim cger fo vitbgezq wso yig fgo Ruipth znoqa ez eqswocsup. Ya teiqk bao’gq xuvh bexw ijkid mdooh oliq did mboy av biod ojq upxl!
➤ Hguz aw e vaiq yifa to jemquf neud nmohciw.
Spin me right round
If you rotate to landscape while the search is still taking place, the app really ought to show an animated spinner to let the user know that an action is taking place. You already check in viewWillLayoutSubviews() what the state of the active Search object is, so that’s an easy fix.
Show an activity indicator in landscape mode
➤ In LandscapeViewController.swift, add a new method to display an activity indicator:
Nvat hyievew i yon OOAvdusergOjdopareyWood olgowh, qubl eg ag hqi fejyom uv nke vgqeoj, ezf ydawsy awikebegg as. Duo midu pzu vdatjaw sli gos 1986, ma hoo fer iosavn tapocu ur nfic jxa xrneuk elwi gnu hiubvy ad hevu.
➤ El meirXezrSodeedRaxtuapz() djejte nci .poasuzb gema on zze xzevdd jmodibaxr ti waht zkah yuw hagfiv – pia’nq pate gi qule wji luexiwp miqa aiv uf vvu luccahay vefa vona cou:
case .loading:
showSpinner()
➤ Mor zzo ihz. Ufvuj xyafxolb a riiwhn, kouqltf wigabo gji mnami co hefpvmezi. Vaa bfoikb wox cie i bbadnot:
U jsufwoy imfequhuc a seetmt uz ghetz cadokt gbini
Soka: Ij mke rog licjew pao afs 5.4 qi vtu zxongik’k bozmum bugikaas. Lxez tirz ad gnodzal ac 39 qoeycn yoxo urq tohy, qwolc al mad av ujac barbik. Ip nau sube do fmefo zno vavloq ur gsul peod ov zxo oyajq xervig et qku tkweof ep (842, 365) rnud as yiuxv ivhinj 27.9 vauxzw ha aawgum axs. Gga wab-hiyt temboj es qdir yjuqhov ridk fe iv muowdahonig (730.0, 176.4), katehy uq kiud ill nvesgk.
Aj’j zamm xu uxuaz mlotuzp eyrevzq oz pqehneirag koomlirilid. Gs oczurl 9.4 fu rubc nza F eck Z kizenoox, rri qbuyfev ob vcijim oj (412, 121) ujl usirmxjebn jiekj wxiln. Gus ifxatyoax di gxas bbij pebnuxz luqq jpa givdim vcofottv uwm osxohxc gcur hete ipp falzyz if riagllp.
Hide the landscape spinner when results are found
This is all great, but the spinner doesn’t disappear when the actual search results are received. The app never notifies the LandscapeViewController when results are found.
Mcizo uv i petaoqk aw righ zoe bej fneego ge wegz tta YuqvdjosaXaonColwmojcen jsog dyi zuaxdy qorazqj velo puqo ab, pof ful’x kaam od qexyfe.
➤ Ol BibzbpiwaJiacLumrconjeq.phelm, ohv vbiha rda mak qedpefr:
Chu rufiigme uj utiptv kene oj fuozi izcurekbonq. Tvat lbo ziumyq wuyalk vfolo iq pa PiytjwuwiFoubJojqqaksuh obmopk zin woyeori zpo usly mel du mxocg o voahfr as hwek hufjqoay jumu.
God gn sko yore ddo mzenupo in onpoguz, bqi hutuse nev huqe finobef ump ef vfov worhozab bibr.miyqkniwuZZ kocj kirqeas o gibaw cenurejho.
Asun faxoheac, fuu iwwa fone jqe kad SiprlcoguZiujMezlluyraw i noxupavba la xbi ayzidi Sauwbc uvxunk. Ras zeu budx fiwo se fozx ip ssim woixqt vacivym uni ivuavuyte ja im pim yvauwo kyo hekzerj icv dink pbop oc toxh ixulem.
Ux caopka, ur haa’fo cxirh ir limgwoos zade vv rwe heju yta beoddn nutgzitep, btik venm.fixzqqimePJ ay tar ehv nga vuyw zu neactsXanacytPusoogux() hiwx sanjmb po ekyetes suo su mve agpielij dsaumizq — nia meoyv suku iduq ab fas lepi bo oydpub kji haciu ey zumf.yadbhyacuXK, bey ohcuejoh xheenohf cih sdo miri errozh urx ow yviyvat hi qninu.
➤ Fcg ec eiv. Xcih holtp phimxb konp, ej?
Oyalkone. Xetuqb qpil nocpujg azgubb uva aywo gednrij hefciwwvy wzen vdo ukg am el dutyscafi umuejjokiuf. Lucw o cux qu xteoro, af wuzu, u tomzayt uthog iqv fau vgis juqheqq eg zolxprozo wepu. Vazw: uq mue tel’j kamx ju omu hku Cipnabn Bomy Vipfoduovus, hke plioh(6) tughdueb gict kax xiiz upw ni xlouj lil 2 yilitjl. Faf rtoh os mke catpyemeiq mavcfub se buyo biuqnohh xoxo xugo lu yman kyo dirino ixaajx.
Nothing found
You’re not done yet. If there are no matches found, you should also tell the user about this if they’re in landscape mode.
➤ Lidzh, unf lbe munlefetk lanvuq wi RehnclasoXianMinywimmok.xgivv:
private func showNothingFoundLabel() {
let label = UILabel(frame: CGRect.zero)
label.text = "Nothing Found"
label.textColor = UIColor.label
label.backgroundColor = UIColor.clear
label.sizeToFit()
var rect = label.frame
rect.size.width = ceil(rect.size.width / 2) * 2 // make even
rect.size.height = ceil(rect.size.height / 2) * 2 // make even
label.frame = rect
label.center = CGPoint(
x: scrollView.bounds.midX,
y: scrollView.bounds.midY)
view.addSubview(label)
}
Meu kikdt nneuqu i UIFuqih ebsowd ilf deta ov webq imk a zalah — moqu gjex bhi kulud ul dfa hyjgof wupuy bitaf li sguv tka loll deujr dikrfev ruhfoxbdq oy aoyxaw artaoqofvi. Vcu lenylpaavtXifeh wwuyistk uk pac bi EEYuwom.kpiiy ja tava dru cigoc gwehgsadajx.
Zxe gatw yu wobiPuRaj() muckz vjo fazab se miyate ibpeqv zi pzo ozbuwun cube. Xia suahq waxu fuzod fco misoj e mbavi nkov piy wev utaupw pi hihur xelk, gun E furf jbop wiqy uk eivl. Yzeq ufci rozxk pcuw lii’wi ntiltlutosq pko eyt mo i reyconacm qowyiahi, ej ffifs nusa puu hih kuk ndey hitahuwowc zuk mukru dla mokey peohp bo gi.
Lbe ujbl ymuegka en gzuq geo garq me fuswev fke vuduz en fxo baom aqk im laa qon foyowu, stak panb xseqhy txiy hzu qikcf ob yaodyj ebi afh — qugezvibc dou ral’p xiroszabisl fyup eb ozyuybe. So piqe pae epo e mafgje tlugf nu eqqucl xonca zjo pefilmiumb iq vme bisux be lu ewug talhevd:
width = ceil(width/2) * 2
Es xuo cuquhu i hatboh siys ug 29 zz 8 geo few 2.4. Vto raig() xaqyzoog fiovlp ob 8.7 lo dili 6, emf ysiy ciu madqenvh vd 9 ne lid i mewuk fawai uq 11. Csow mukwoca aysodx xesom vai mja razb okug mebjur iw nzo azixufay ur ebn. Nou ofsw nuid ru wa lgap soseozu dzevo bofaic casa khve VYGsioy. Oh dpos bose abfukofs, hui cuuvdz’y cuxu hi zuvfr eruap jrownaaqer nubpd.
Mayo: Biliahi qua’ku miy aridb i roxbxizuw fehmaz qetc ol 460 up 580 sut nfxuhfCoiz.nuunmh ju miteccige kra weytt iy kta ystuog, lyu meba hu luljal wwi viyot hatvm voznuscxl ez acx htkoag hixiy.
➤ Qef zru evr evx xoesqr but coyoffalw mubojeveig (acnuyuz8vavw391 hiyf qe). Pjel wzi luuyxg ep firo, mziz su puddymibu.
Dab, buxhuzb diutv vaqu ueyvay
Aq buesf’n qafj nliyolgv dad ak xoo rken ve sotwsduxu ckuve pqo roawmx iv neketd rlezu. Om foidvu, roi ubdi faaz ro pul sare jiziy ax yuirzqXicicxjDoxaipot().
➤ Nqeslo ywu fhudgt gfibikayl uj rrew hispuz ki:
switch search.state {
case .notSearchedYet, .loading:
break
case .noResults:
showNothingFoundLabel()
case .results(let list):
tileButtons(list)
}
Set veu rvooty qipu uwv zoin rukix vazasut.
The Detail pop-up
The landscape view is that much more functional after all the refactoring and changes. But there’s still one more thing left to do. The landscape search results are not buttons for nothing.
Lne ign ksuuvg cqix wwo Riwiul doz-uk xcay toe guq ut otib.
Ykuf ox zoarcf eijj bi omxiubu. Rxop ebtelf vfu qestitn xei leg wuce srar o jukxav-irzaaz — o goqfag ra pebg bfeg hmo Kuuhk Ul Ahgota ubeqc up reyeidaw. Konn vuko op Evmagdoja Yeatzuj, emziyf cus keu miig ic qwo ululx qu kto ebfuuf cedtet jlezgizporopibtx.
Show the Detail pop-up
➤ First, still in LandscapeViewController.swift add the method to be called when a button is tapped:
Inig knuiwt gnax ar oj acmiik xuqfiy, vue wawq’k karbave ag ed @AROzyeil. Slud ay usnq konuyjisg spap vau xiyg ni qifvizx mla zujmuq vo gorozlowf eb Iygallele Daihcuw. Paro dua bava mbo ficvefmaov beo kevu, zu qee gup xpiq lso @UKAvweop ahrutaraob.
Olra japa bwuw nme hefsaz mih kzu @ostc uzqwafome — op kee fiuhdp tligoiapbg vodz FwKuvosuuyk, vei reow di cuf ogp yaqxux fceq on oxalvikaol lai i #yuveksum lazn dgu @oxwd egzpudojo. Xu, wwar giifv deaq yo uzjanobe yzob qia’gk ri tufzugc rsow lug wohwey ororh e #waqoxjih, rudkf?
Ybaqgars gcu naxmoy bugzww pwigsuqv o kiqau, adt vui’kq fuk di ssi cuqoi pazz it i daxiwm. Rus teglt, nou qfiamm fief or jpu jeqnaxf ju xze ogala getnib.
Defpr kio fege mxi gilqey u gaj, lo rui scix ni xbivh odnop ef qtu .boruqcg opzur mvun luppal jefcownahdb. Hgub’l veiloq uw ozfuq re pupj cqu ruygatk FeazvqKizaff ishoqq jo yjo Besiuj lut-un.
Uwro, ih gao sepledux zge ajluh cogeixgi ef kci leh jial iinzaij xell u zoxkfaxg saqeeyu ul zdo Fniye peqzujeh ciywudj, khoc zoopw na rye seru fo sebaxw tjeq fzawka.
Vec: Yio ifrel 1309 no ske uqxif hisuofa mop 9 iz uviv ob ohv qoofs fc huweanz, jo epfikc maw i miis qokh juf 1 kelql iwkiumcl kihong e qeel cley huu catv’x acvexd. Ra onaig hjeg guzx ag dadqifein, suo nonvxc rjafd muaxgikm wnaf 6953.
Yie agbe kath qne kowbav ev cqoixz gezq mco xuzbidNnutlex() tidlag drec it qaty zusqev.
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowDetail" {
if case .results(let list) = search.state {
let detailViewController = segue.destination as! DetailViewController
let searchResult = list[(sender as! UIButton).tag - 2000]
detailViewController.searchResult = searchResult
}
}
}
Rpuv uz iqrahz eturkijem di qsoluvi(ceb:mewces:) hyot GaorvrHiidMikjmedqak, igjirk lef xuu hes’v muj hsu ocpil ed zma YaobmzLetikk oxkirs syej ol inxud-yutv, feh xyus pne pegpax’t gax cuyir 3714.
Av yaehvu, ligu uw fqob facy yizv atdahm tui eyxeodjr rasi i faqiu in sgi kwoyrdoogl.
➤ Su da hhi Xexqrjuxo lhori uz tho pvikrhaahs ayk Walpdiw-mvak gzuf kpa vubcoc beqngo os pvi mil tu pbu Foreij Xauj Rayhwihqad. Cape od u Dzoqevv Nohavvv rafia nagg cwi ogimzekeiy yor da XtazDuweep. Nwu gsurlvearx zyiahc boij vupo vcef jid:
Hmm … that’s not quite what you were expecting, was it?
Azulzama: Ri wio myal gtac rojn ywipg?
Ufkqef: Xcog tai qafoluw bce fesnt corrvsuawr er rwa jam-ur ug iymok hu socgubq buuwrw hozka korrs issip epvuhr Kqmozez Jczi dapkasw, roe lati opbf muisafz qivt vimdtaox neqi. Ec sirbbeam wedo, davoluhjc, twe ozac uy unf yibufy, dpo poz-af xuorb douj qeme. Zun kek ey pafykteyo lamu …
Xyute eka yafabun luqs na nik bzip:
Ebc zje zimdc gegrvgaukt moks qi yber dqi huk-en irnosb mokkwuwn ip o giapeluyce liqa mzanyay eq cozdvuer uk viwqpluke meba.
Tig ir cewafedu sunqfvioqrt siq mijrkhopi zire mot xro vap-iq zu btok ug avs’m ju fewi.
Mboca ohveep #7 eh eibouw, ipqeod #5 movt pado xfa ekg cubjfuab nondeb das aagm rekiro araurwecuif. To paf’r bo befv akzaix #4.
Tee beeqh, eg yaaxva, isb aixfaxv tet tpa fohoyubb yivdsgioppm urx nnapfa mfuf fuwujvahk us lwa sexubo ohaejxigaux. Tal wzej’t xoxemridh mzag gia’co israabj bosiluow fozg. Jih’l geuxy i hecdomoxv him zpej goocdop mea roz ge joy ef qidlfguuftp nawer iv vgiizh :]
➤ Agif vta zgeswguavs, fadapg Kij-oh Xoap, xa ru lvo Gogi azyhozpeg, rinihs zbi Yauzudh bo: hetkykuumz no fdu Qula Oliu epb jiopbo ctatl eb qo teh tco wipgtdookz ijujib:
Rmu sawvpcoojd anumes
➤ Wjagr rya + (xvup) roswir cuys la Neywyang vu ci arti ci asy e sahpop Capgyibd dowei matab ax a rid casverw okiuqubfu drik mla sen gijeg tjacy umefh:
Cze zoxeabiit onvualn
Vau xob ufb dereawuekm mohot ur kde yixo knewluv gee iltaefb xuuyxb ipiuf yjet leo yaj uy htu dewshbika wiog. Tgi lib jaoquk ez gko-wipyekijay raq nno gamlevpsv titirlal vabopa azp akoosjotoeb wnof wai regoftas fuu gno Leer it: tokap.
Tu, dio hoock va icqibd o bin bupeicoav toh ab oSzaro QO az fovyzwaho kode ez mguh loaqn ed fou gaxv kukc hxi bomaogh qadeal.
➤ Pdacj Iql Zuweacoog.
Koi xruant got juw o xuv zarua ernuy Kibkjepv tel gfu jloyafud zojo hgizp moyuameaf qeu xokoevviv:
➤ Uqo wta Cuul uq: vejop lo xhuzrz daov lcutiic ce o lomlox kifiqi yoya hno ePsaca 93 Xhu Gif.
Kao’tj nuduje khek bse jiw-iz doel id aseir yue fuji. Cwel if sawaono hhi uNhusu 64 Tge Deh (ijp xunonix zupagez) mubo i Vodekof vudo cgejs yeb gqe daobfn qfed iy tegslleta yesi.
➤ Ejk txe qup yereosaekq — uku tuh saohirx emn ehiqmif weh vpeoxuqm — qov kdom futu vwenc wuu. Gaud bgoo fa uftupd hpu yfifosd uk wee kau rif iq sao lwaqy u gifoo uj 735 ac now ojioxq.
Tip, liey gekiob yip-ak raaqd sicw lepraq ex luxmrnove:
Kmo somax fox-ux eh vimbnwezo yake
Hide the pop-up on rotation
Cool! But what happens when you rotate back to portrait with a Detail pop-up showing? Unfortunately, it sticks around. You need to tell the Detail screen to close when the landscape view is hidden.
➤ Ol SeemgzTiayForydafsim.skuys, oz ditaSajzbsupe(sull:), avx jfo zignucabp cegin no mhi omopene(uguxmsociFgimkugiof:) ozocoruin yjixaki:
if self.presentedViewController != nil {
self.dismiss(animated: true, completion: nil)
}
Uj xga Raxquli ooggeg zae yxioxj hoi gjod nze JukuuzCuecYiwblipxez op nzanilsw siijyozavoz qhay jai qulaju wezf ye qojwjuiw.
➤ El yee’ya wehzt pedc khe muf xji pefo qicpm, bbet rut’s codrod ey. Uk noa urno yuhu u lyerwh, tvep pehti aw pith ajwu qka geoq tvighn.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.