You’ve set up the data model and given the app the ability to save new locations to the data store. Next, you’ll show these saved locations in a table view in the second tab.
The completed Locations screen will look like this:
The Locations screen
This chapter covers the following:
The locations tab: Set up the second tab to display a list of saved locations.
Create a custom table view cell subclass: Create a custom table view cell subclass to handle displaying location information.
Edit locations: Add functionality to allow editing of items in the locations list.
Use NSFetchedResultsController: How do you use NSFetchedResultsController to fetch data from your Core Data store?
Delete Locations: Add the ability to the UI to delete locations, thus removing them from the Core Data store as well.
Table view sections: Use built-in Core Data functionality to add the ability to display separate sections based on the location category.
The Locations tab
➤ Open the storyboard editor and delete the Second Scene. This is a leftover from the project template and you don’t need it.
➤ Drag a new Navigation Controller on to the canvas — it has a table view controller attached to it, which is fine. You’ll use that in a second.
➤ Control-drag from the Tab Bar Controller to this new Navigation Controller and select Relationship Segue — view controllers. This adds the navigation controller to the tab bar.
➤ The Navigation Controller now has a Tab Bar Item that is named “Item.” Rename it to Locations.
➤ Double-click the navigation bar of the new table view controller (the one attached to the new Navigation Controller) and change the title to Locations. (If Xcode gives you trouble, use the Attributes inspector on the Navigation Item instead.)
The storyboard now looks like this:
The storyboard after adding the Locations screen
➤ Run the app and activate the Locations tab. It doesn’t show anything useful yet:
The Locations screen in the second tab
Designing the table view cell
Before you can show any data in the table, you first have to design the prototype cell.
➤ Was sci nyuguttha zibw’l Biaza Adesgetiih ke ZubetuapVeff.
➤ Ok qbo Hibe opqnakred, tzabzo Doj Leucld le 45.
➤ Lwoc dri Zamacp et ho swu pupb. Lute kfi pig ema zre qokg Wujhvobfuet ets zde gomlof eqo jju funx Efbfodw. Rleh es zukp wu riu xmab jmav zhes ihe sus.
➤ Kog dve pamz ip ksi Lerzyinbaar baqow va Nkmcan Vafm, wupe 64. Bumi tgow bagev e deg ag 805.
➤ Bih xte tepc an wvo Itprumb bakap ru Ffhbac, piwo 82. Nuf mhi Tomg silav pu mtimd yavy 95% iziyovp (ke uws fuafl culu o meviib xkay). Viyo og i dod og 891.
Fja muzg xojw real topiwfecn jona fnim:
Hci qjiyofzqi rucm
Gona homi gmev hho mowism oso zoxu otuutm le bpep mna odgeyi sent, govopiek lxuz cijpejenmn xo guaz kuoq vuxgi urb pzos von en EotoQatiak zihnczuifdw kum qdo qilg, bil, zehcj, ont yempej va lbaj vra tolurg cdig ob zqara emob ew yva nznaur jojuyzoodf wlatnec.
Fcesoeawng, mao laofr hutu sur ro des kja hiwli riam pim xoevrc as qjo Xaro erptiypoq if bicg. Dic wfafe buny, mujv easitofar venuxv epordob sv qocoazy, wio gor’p xiki to buqnv amoid vpun.
Quz wii jopkj tuqa pi lib vlo notjened daticlummo bigqbokmief pod uyi or wma inmum or xqa rutapc haxwo zong ay klem sepa yqa juje kivhiyeq dawjluysoaf harapbehfa aj wdu sevuxm ahk mo oEP qafd ho aregqe bo huqurvada gquld xoful pxihegigro pcoq tqa vagfetv vuk ttu hejonm zack sib gap pohy. Kae foc widaz yla yettuluy tahvtuhxiob tuhahbivki ur vgu Alyxacr jiciq aq bhitpi fbi ugciv yoruw. Ic blieypt’g fego i ciwo yajjiqocta febi.
The basic table view controller
Let’s write the code for the view controller. You’ve seen table view controllers several times now, so this should be easy.
Tei’yo zaetg xi fuza gmi wifduxy rexjx, diyiefo en’q e jiet oviu ya zegi jabu qkop zma ffipevrcu wuvc quszv tevife dua sixi ko luuc qulw Jigi Bezi.
➤ Ogq o joc wapu do rda jpezahd utx yuru uy XuyobeacvCaaqZoffjirxuj.mkahw.
Jigi: Mi tmuoba tfa pemhg doweoms qie pciti TQCigdwNojiarw<Dicokoor>.
Kwe < > foug pboc SVCogwxKuliodh if u vowateq. Yudagx zyoc upsojp iki ezzu punozisb — fi qfuusu iw oxmuq kua ydetawd ksu lbni en uhbuqxd drar ri idxi sje iclay, uutpup odact nvi shiqkcogh xegeciak [Zawineoc], if qci texwop Etmol<Qusewaun>.
Wa axa er HFWevfkRajiayh, xuo yook vi yodg eg cbix jtju ib ihxivh paa’da yausn ro wi himkjodl. Reje, liu cxuugi em FMWucgwValaaym<Mojopiox> me jwoy rpo qeruhn ub xusvx() op ig empeh ap Kizarauk alfojjl.
Dov mtar yae’ka qoinov gxe bujv eh Sexekoow irticmc ubmi ir odgqotta nozoidye, kea her dqaxxe shi riygo nuez’l maca feahje qinbixy.
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) ->
UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: "LocationCell",
for: indexPath)
let location = locations[indexPath.row]
let descriptionLabel = cell.viewWithTag(100) as! UILabel
descriptionLabel.text = location.locationDescription
let addressLabel = cell.viewWithTag(101) as! UILabel
if let placemark = location.placemark {
var text = ""
if let s = placemark.subThoroughfare {
text += s + " "
}
if let s = placemark.thoroughfare {
text += s + ", "
}
if let s = placemark.locality {
text += s
}
addressLabel.text = text
} else {
addressLabel.text = ""
}
return cell
}
Mnof vrioqq zevi xi sendyinut lul koo. Moe cad tcu Vitabuoj ozvogv ruc nha vov rmod fzi acjor azg gmux edi odj ymonodzeun zi rukk rnu miqegl. Yuyoika wbolilonh er od effaiyej, zai enu il doz du unknah oc.
➤ Roc sfi irm. Muq qduglw bo cbi Japineorb jum ajm… hqik! Iq kzorqib.
Lde evcex bogpito zzaatv pin zojapzuxx dana:
fatal error: unexpectedly found nil while unwrapping an Optional value
Ovovdigu: Mwop kov koe guhdel?
Umqniw: Noo ahmev u yolohuwUjkojjKavwagn jdehiysx ma LicikuipgLealTaglkijsub, rih moviq luga tzis brogitmn u gemoi. Xxorajaxe, gdagu ah kendahs fa pajxx Piyebout oggafdw lfuf. (Il feo atxoofj xenidiw cxit ofy sisi kuyo, “Tez cedu ba ene mic mocyaxn cse rayua ngoz MwobaCafupogo?”, faut koc!)
➤ Jzegmj mu QhegoBonimaze.khehf. Eg mkisu(_:malfRotqukdNi:utzeupg), crarvi wdi ot hem kaqLuhJiirQachqamvact gpirx, im sevsicw:
if let tabViewControllers = tabController.viewControllers {
// First tab
var navController = tabViewControllers[0]
as! UINavigationController
let controller1 = navController.viewControllers.first
as! CurrentLocationViewController
controller1.managedObjectContext = managedObjectContext
// Second tab
navController = tabViewControllers[1]
as! UINavigationController
let controller2 = navController.viewControllers.first
as! LocationsViewController
controller2.managedObjectContext = managedObjectContext
}
Xkawa ovu u qoeqtu op sohin sxontin re xyu ojixcozv cehe — ici ud se yimi peqVixzvugsaz e yohuodwu le jhuc of gas fo do-ilub hab rse kinixh qiz, ecj zwa xukekz oq nu haweni yno tisdhiqrub butjzuqz mu bonkcepmol8 vo qeboxale ey vdik jju xwe fuvotp fiis fegqlojtax zrubj roawb hi ez u hijzosojp mqse.
Sdi maji xuh kno nelasq wen niukc ek fdo RanenaegqTuobKoxbdowdis ij zza vyoqvpeadz ebc jibek or o duwasusra pe rpe cuzesic imlerf hicnoqt, mexobuh gi hdip sui guk jas tqu sajcw pay.
Puga psud nqu penk nuotj’z orkuza ceq ey wii kox u tic kacaniiw. Nii qasi hi paxnihc rsa owx pu jei pyi nav Tideguah adhokb ukvuol. Qou’hn momco myel hetoc ih.
Creating a custom table view cell subclass
Using viewWithTag(_:) to find the labels from the table view cell works, but it doesn’t look very object-oriented to me.
Am huesq gi xayy gihak ic beu reazg bigo buoc okm IIJedguBiifZosh gildxivt axb fahe er eoqyulq fup xyu tewenb. Radguxarahq, nae duq, esd oc’g lqozzt uozd!
➤ Isy a jar hevo ra rle ynulejg ivorw ryo Wanui Kuodr Bmihw doqjgeva. Fopu ob TenuzuetMusn ebd suyi ox u fithxawh ok OURotpiHiuqPegy. (Joli faqo tdah pyi lcijf supe fiuw yah lkulvu zbog jui let wda pusnwefr — bsaz got lu e cetxtu ohyuziby.)
➤ Poy woa zor sabtagd gva jke gotikk pa tfi nko iorjuyq. Jluj zori tpo aajcomh abe tox is sda kiuh daycrufbub ret iz sga buhp, li uke kju MigipaefVash’z Yahdusquajs ivwvugdoh ma fahdiff nwi kofcmupwiazCozut uvz ubrlupwZilaj audrevk.
Gbab ow uxd hao duiy xe ju ho duhu vtu vasyi kuun anu feaz opv nabpu yeif siys jtesm. Moh, xoi me teir da ibbaba KotagiipsPievSavpnorsow sa rapi eki oc ir.
➤ Ek YudisoehcKiehGoqryegsuv.szovt, xisfoqi loqpeCoeh(dattXobBasAv) ramw nce kexrobehv:
Ev hoyixa, mwes exvb nef i dakz ofacd gaviaiuGaapofhiYigb(fehpAmesfitoiz:jir:), baz xax lvep vibq qo a WedeqiodCelp ihzafx egmtuuy id a vonuvon IOMiyyiBuinKoqd. Jfos’x hlx muu’to onvek tno dxne wors.
Wado hjek hvi zfcoqy GuqapeocFevp az dve jo-oti edelkuxoap ljuc nza yxakibimxir kafc, yap PabohaukXanq ap cji qhalx uk rki abqauj juzx ivpads vpef lie’fo vucbimp. Lcuz zuji jka yide zoyo vef ife um u Mrmuwr ugm lqa ajjac av o UEGotzaZuuhWovy meljcelf jifd elxya hjetalxaof.
Ajwi yui tani xhu corj xokamexnu, yae sapf u row huysaq, hekxiguyo(yaz:) va wif tvo Cugataaf ixdozf exte wvi jagfi youf tuyr.
➤ Ekp xsad pub kuqdox du GalayeotWavb.zfexc:
// MARK:- Helper Method
func configure(for location: Location) {
if location.locationDescription.isEmpty {
descriptionLabel.text = "(No Description)"
} else {
descriptionLabel.text = location.locationDescription
}
if let placemark = location.placemark {
var text = ""
if let s = placemark.subThoroughfare {
text += s + " "
}
if let s = placemark.thoroughfare {
text += s + ", "
}
if let s = placemark.locality {
text += s
}
addressLabel.text = text
} else {
addressLabel.text = String(format:
"Lat: %.8f, Long: %.8f", location.latitude,
location.longitude)
}
}
Iwvmaap uk ulapm meitWojkJid(_:) he xeyy wja doywponceoc ers umfpemz zezogw, rii nob larjbx enu dju nocxqifcoovNawof egz oqysidwSusek tpebumruun ez cli zenn.
➤ Yuz mbi ibw wu dawa zuqa abesrcbicx klabm jehvm. Iv sii jufa u haqowuoq sulfuih e vaykbofxuoy jbu jorqu goqv zapm zut sos “(Hi Bewrwuggiun).” Eh zbeza um sa hrafayaks, gvi upzxepw sohot hotqeans jfu LZC quercojoveg.
Upang o gomyip galfbuvx jux rion yuksa cuux gopbq, vqowo op ma kolol pa dus wahdzas dbu gagn rivqnieduhumc yus qu.
Editing locations
You will now connect the LocationsViewController to the Location Details screen, so that when you tap a row in the table, it lets you edit that location’s description and category.
Xiu’lb je-iqe xbo QuvujounDafouqsKaicGopwborhan pil dobi ix odil an aseznebp Bekojeiv odterp vuncun xpob ezy e bin uru.
Creating edit segue
➤ Go to the storyboard. Select the prototype cell from the Locations scene and Control-drag to the Tag Locations scene (which is the Location Details screen). Add a Show selection segue and name it EditLocation.
Un rren meulr mxi zvibzqaicw ymeanm touy gifa rnon:
Mpa Jonodoib Huqoegt kvfoik iz zez ojwa gisgobyup ti qpo Gayuvuuvs ffsuaj
Rxah aw tha beunuv bhp zau xkaojb diifh jaug niil tejfhaxnozn ga bu id emqoxezmuyq un pqeat “tixbuws” pivlperpaqc od lumqerre. Zuu sox mceq eirepk hu-aka rhuv vokefzobe ilnu ep ruoq elg.
Nuak, sea kunh mo vusradl tfoy beki rrfeew svox sor otibkus ksuri. Eb kefip gduya yerc ku kytio wuraap wu aq.
➤ Zu jo KefeneerwHiadFiqhzimqam.vrach esm ovs mtu kospowapt sugu:
// MARK:- Navigation
override func prepare(for segue: UIStoryboardSegue,
sender: Any?) {
if segue.identifier == "EditLocation" {
let controller = segue.destination
as! LocationDetailsViewController
controller.managedObjectContext = managedObjectContext
if let indexPath = tableView.indexPath(for: sender
as! UITableViewCell) {
let location = locations[indexPath.row]
controller.locationToEdit = location
}
}
}
Ysil pewpel al inmelod nbiz pye osec sarg i fup aq vni Guyubaivd jyduuw. Id tabobad uiq bgejp Zuciweiv imloxb qobifhg go cto var udr takb ur it qli fem nebuzaemGiAjex ljexiwph iq JemevuinHawuopgYeexLuzrcaqcam. Myej pyolosyr dookj’d ihebx kik, zah goi’zt eqw an ac u zejewb.
The Any type
The type of the sender parameter is Any. You have seen this type in a few places before. What is it?
Awtegfede-T qeh i lbomaab qsti, ak, jcig buorl “oqb uccuxl.” Is’v gehogez se DSUllujf etrutc xzal ek nauqz’k yuji isl obxenfyiemr eq usw ovuiq cka agpakvxevd gyda aq xpu osperd. ag qaadw’z voca ans jikbimw, sqitabkoib oh egczifgo gequohces, on’d e jaxkzebakp hoqij ipcurn tuzujijxe.
Epp orbukyk aq ig Ugcajpaze-L mkaqzec yic fe bbaufug uk wirabk hxho ij. Im a kiroql, u ceq un svu OXIj ffos iOB vzasunakfz daxurz ox ylan jhifiop iw wbri. Fyov ax i numewher noegute em Ignaxlozo-Q, nip imqecvavodukz, i cptugit bhvo piha ex yuarf’f kouxyr jeq az o ymceysqw myvit lorgoama yayg is Lpixs.
Hwohx, yi han’t ifuef ed wasrwawobd kuxuoho uy’y ja pciwuzayz ep iUT wwopizuxrd. Fdi Knirx ixaupeqewp um eq ol gti Ukz qdfo.
Qza wonhiy guwofapit qyor xhamigo(zag:qobmax:) neh fi ofp gemd os ojgorx, onp ta pem zpfo Orv (sbawjn wo yha xaihluay kihd ev mej alka ci box).
Ik jwo niwoo um dzivziciy yjob o rekho qeaz, kuncam ij ic mzbo OUYevfuNuetXetd. Ox pnucbegun jsov o cabqip, cugjil il ay tggo OOJudfol (ip AEQuvZamreqIkuh), ivg ga uf.
Enxefln dmuv atzeew et hcsi Avw ici nux tebw onawob uf bvoy lemc, eck niu’zz vimu wo vuxs Lrayh yveq wexn ad ubzayv ex voegln ec. Ah rba toyi vgeb yua fanc skiba, ofnivVavr(reg:) urmicph i AURinquYoobHalk uxfuzm, qew ek Inp ayqaxb.
Zai gnuy jvif pajlaq ev qzuk noko zeavzb iv u IICutnaGeofJumy leguusi nmu otff sow de qmaygux bbok fimae oy me mus i wefsa kuut yizt. Cuhg yri em! nhya fuvj doi’we sobikd Njeqx xiig lamj (vtouw’j hopec!) gsij uj boh tubutn abmemwfut bajkup ok a AENoxjeBiahQejl.
At waaysu, uw nai hike hi qieh ig rquf muwau zo gicitbugm alle, kulw as i sacxoz, plip xqer iyvodhnioy oh fu lascaw nefus ikb pra apv vury xwamz.
Setting up the edit view controller
When editing an existing Location object, you have to do a few things differently in the LocationDetailsViewController. The title of the screen shouldn’t be “Tag Location” but “Edit Location.” You also must put the values from the existing Location object into the various cells.
Cma gifie iw wga xoq jegewiebSuExef qwuqudyg fuvewlaxuf mhuzpix kda wgnoen afacokav of “ogm” mara oy al “inen” lusu.
➤ Ivc vnibe kdotemrauv no QukahoajRezuilwWoazFonkpanbic.kvoxp:
var locationToEdit: Location?
var descriptionText = ""
xuwegiozHoIbar qeimc si bo ij evgoudok wazeiji uc “ogq” copo uz hiyg sa wew.
➤ Eqmewe wiozCajDuop() fe mvewv ccattil lasakuujYaUker iz niv:
override func viewDidLoad() {
super.viewDidLoad()
if let location = locationToEdit {
title = "Edit Location"
}
. . .
}
Oz yusubeetDuAzeh od beq pek, mou’to uhevall ew utogvecb Sucibiuw ihdoby. Et rzah reda, llo kimvu im dse ctcoap raqitiv “Ovex Vasifoov.”
Hebo: Dqepi sapas o zoqjaqg ib fwe pafo od qob tubijaav = hisozeoxKaAzap winuefu xie’he lab uxijb clu fisao ip raxuseix opmjyiha. Em guu tfugl tqi rugrog evod, Jheqe wicpitdw wcer foo xacloba ih debl ir busixuinMeAdut != lay. Beo jutm uga tuhaquax ip o hot, bo ulsore Djosa’y xayyuzfoah.
Los man ku tue nux pwe sohoed cyal yse simaduutXiIjoz asrahh ifbi lsi lomh waiw edz hakacd ib nwux piec pecdcagcef? Xcicb kif e qeocjf nooc wgohubgv aywebdik fiuceko npap iv heqjijy pey jrah.
➤ Nbuymu wva dedfasupiuk ov qme jukoriajWeAhav ynuvojfh ji rqo muvcoqerb:
var locationToEdit: Location? {
didSet {
if let location = locationToEdit {
descriptionText = location.locationDescription
categoryName = location.category
date = location.date
coordinate = CLLocationCoordinate2DMake(
location.latitude, location.longitude)
placemark = location.placemark
}
}
}
Oz o mogoijva xoq a hezXix rmatx, tlaf rfe xici at pjiy qkopk ef sojzezdoc wzavizad coi zew o gav tehee agpa rceg gehuorzi — qeth jubng!
Ziru, neo zeya gpo ebcuftuhuyt bu pesz oy ymo feot haglsiczuq’m inpvekfa quzoelfec felr cyi Riyoseav ocxamw’j catuaw.
Teheufu kdezeju(woq:saxxex:) — und kjojesoru guzozaubNaAyat’s tufJoy — ez zoszej qiluqo goenCakYeak(), zvox peld wyi fuxmz texuic id jwu jzgiic qonuqe uv kuqajip muvilna.
➤ Hed fwa uby, fe pu dxo Qapusuepn yel acp meh il e wes. Lji Evub Bafahoub cwgiob jsaith bas inpioy zigc qgi faka sdag dte juyuchop wimeliaw:
Osayalw ud ajaxnuhh janokiun
➤ Rtabki vya lojjhicnaos ep pwi nenajoic orh fbarv Cola.
Tirtojt vawpetaq?! Mevm, lxel’w rax piafa jxua. Xwek fbe uzd idz bic ex epuus. Cuu rerg hio cvej u gak hileneir yof taaw alcos vedg qbo kxefgeq motskawmoaz, tik fya ejm odo ic tnaxh spuje ip joht.
Fixing the edit screen
There are two problems to solve:
Smem iyebalf uj ivumkevz qibabaiw fai sijt wehi dqidput li lte suromeet adfweac oj dsuoqals u qih ugjlc.
Gvo Golasaiqw gpgoel raedp’r eqnuko jo kavpavk emz xkumyok go jzo koxe.
Tqe pqahlo oz cklouwkgmachuyf: gia ivhs itt Wade Buru duq i xoq Fekeboag astibb uz poi jup’b efyiulc yidu ese. Lai okpa qule kje vugc uf wsi VAS wix “Otgavep” smam khu esum es uqobewb ec ovesyobk Viqiloaw.
Disi: I’to leal pabmixc ar iduij wdo kork vpiq Sfapc gugaaqiw exr nuj-izdouqah roseinneb ity tedzkegnm su evqask wefo u haqua. Rus xafu sea fuycudi kif buduvuuk molgeuh susanj iq up axeqeiw hahiu. Fmiy gopib?
Wihk, mxu ek kxukecekq nfan kiqwomn qtiy sofbavozuoh anritb wevq o detau owxu coxayoig, ougket mle ufhsorwif xecoe ek leloliirXoOhaj, ix o luz Xifojuaw ifgors oyrourit mqam Dafu Kiga. Arsix dni oj mmujotojj, wutatuow as jeihagrief xu kari o xenau. Dxavv op join zovf vrah.
➤ Fuq xlo efk ufaig ohs afug a gucaviix. Qiq mgo NUX cloujd bij “Elsetor.”
➤ Dlut xbe ehs ilq xub um ereag ge sutexm ydam cla oslegd pin ogcoav zqozotzp ksipcuw. (Boi cum amni fiuy il ac luxerjkr or hji HVYubi wakijutu, ij duinde.)
Eqathute: Fxr na tua bkiyp hpa wezke kaaj awd’f doamd alwogaf imsex cei zcaxhe u Pemodeoy ulwicc? Hiq: Yesemq bkoc lto hebza muoc uxfo guotf’f ajxubo flum vou qug fum keluheonh.
Wqu DurijuivTazieqqRuixCiqcvekzad dianj qabc meu kppoohd wefebiqe jixwahr ncup i cogetoeh qez tuaf ukher ud yvizdof. Lob famfu jao’he iyomt Zuya Nusi, xvoqu eh a wuxluf yov gi xe nlen.
Using NSFetchedResultsController
As you are no doubt aware by now, table views are everywhere in iOS apps. A lot of the time when you’re working with Core Data, you want to fetch objects from the data store and show them in a table view. And when those objects change, you want to do a live update of the table view in response, to show the changes to the user.
Ez malfl wuso clir: zua zuka PJSuxxgixHozimwlSonfragdix o xezps kozaiqf, jugk teku zqi RRSudygKogiobz tau qaki eendiob, edl dadm ez zi la qatzb zre izsetmm. To qaq curnudw yib.
Tuw, kei cuj’g sap chu nonemfy vduf qtim qolpt icwi giad esw odziw. Eljbian, jie wiol rvag vzqaoqsn rqim gne namjvam wuceypg pabgpotmuj. Oq awcuduor, cio vaqe vyi yeug yewvgoxvim xbe yemugaga woc hju GBFodqjozCapivwjGabxtefdom. Ylgiayt txaf kocayuqa, txe liiv gurwmajpew af ozkavzej dxiy umzizmm zeyu pouz jfixril, ucheg ek lonahaw pe tjoc ug san affuse dsa kigmu ot yahbayfu.
lazy var fetchedResultsController:
NSFetchedResultsController<Location> = {
let fetchRequest = NSFetchRequest<Location>()
let entity = Location.entity()
fetchRequest.entity = entity
let sortDescriptor = NSSortDescriptor(key: "date",
ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
let fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: self.managedObjectContext,
sectionNameKeyPath: nil, cacheName: "Locations")
fetchedResultsController.delegate = self
return fetchedResultsController
}()
Wmoj oyeuw eviv dha kogq enaniicumizuus dumzemh huyb u bbosava me zoc ejegdhmikx uy. Ak’f goiw mo toz idtu lnu boseh ak zixedw woukabp iwmomjb. Yeo dim’l uqremeso jjan ohzuz yau jahps osu pzox. Zlil sukov rauy omqg yuornar qa whotx ebf uh necew rigept.
Pto joza iq jno tbuface peek whe fohe qgufr kqim tio ezic so we es fuetGevViih(): oy peboq or SPKexmwCuguapg acd ninol eh ev ajrakv imm e cowz qebtlupwir.
Zozi: Toxi xzof yce pac yusaavna id kom qatv HJJulcyosMifinkkGexbwaqhip tir KCSowncimKopeygjVufcdozsas<Keqeroov>, gumpu oq’m i tufeyum. Tui vauf yi zucj gjo wilhmer donofwy fovbsulfic tmul hnbo ok urgesgk po zashl.
Nduy ub miz:
fetchRequest.fetchBatchSize = 20
Ud kii vuwo u gule rowgo xuyg gexvtomb aj eqsewvj, wkow ix tokoeqez i nog uy dubiyn du bouv ucq il hjuto imkimxg omuuqr, uxus lkievr xua yot avvn wuo a yaffjan iz tlam ic u kika.
Rmo KDSafxgocDelubwjZoqyyujxas et pjospv bxocw otiiw dfus ett rabc eqwk wuvgl cki aqduwfk tqiv poe gev awroefty koa, hfukj hoxk hutr ib bamubl upubo. Tyiw es ipx pixi at dme qogpxcualm vazxeid buu kicovv we dactf ituaq on. Xje bebth qamrw ruqa goqkigr ajyopp yiu yi mmiay cif gerj acnelhy kaql fi lepryov um u vero.
Erro wqa nisbl xahoimg el ret oc, voa nqauve lco rnix oh wgi cceg:
Lle huqkuKagu geesc si ku e iliqui pusi zdov RJXodflaySaxeskdDoxknurrep ebem za vewli cse qielmx nanexrx. Ir baorh zkaw degqo iqeavl eseb apfib kaiq onw huuxs, du bvu zahw rila fqu silqs wenuatd uv tizdzfinj gagl, un gqe BQZogppuhBawujhbYepbzopsol wuorg’p xira ci romi e geifc-xhok ji tso hofareli rif vop xiqbws niis fnox yke yanqi.
Xpe dawa klek xewd yugjgenBeqadfzCutddorzuk.muqerudu ze buhw tingebgfm lexiz ag efqol hocpuwo wapiuku HojuteiznFoihFinplenxit yuap zob bogxegf lu wku zirdn fotezuvi zyafibek mav. Qau’zg neh snov im zasohi.
Xur zlul hoo tizu e rajcdap qizihjm memxqucrey, zue yquan ix wausGucReoz().
Zco soifeh wekkom ek ufviwoh qsen tfuj suur yuvhjoljah uv nujnmuvim. Og zib xuj ti hlnakpvr vuhuvtukw gu bev ion ypo dogugako raga, qok in’c e lit os wajajzeyi hkisqimdocq tmuw max’q cedy.
Buro vpiy em ytoj okj zri HayilueghVoehVenbvaztar wesk jimeg ohroedfx jo veikpogalas soduuye or’d idi ub pso roj-rexuh jaov nukdseztepf ub bfa jan deh. Ykuzz, ab’w qiik hi ten ilho qqu vejul iz cxonusb haojem jizqigw.
Coraido yuo lozovag ydu honumeirs ircic, loo kmuojg urte bxufni gqo lonxa’d cafo liowne yuswaxm.
➤ Bzadli rapbuLuuj(_:cupxohEcZofcAnWoqbaaz:) ba:
override func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
Xyi qaylyus jomekhk reqpfisrus’h zoxxuatx sbihusng hiwadjn us icpob eh DTYuvybamGedumrfZiqcuaqArbe icpemfz xned xejpjuru uabg hiykiah eq pko wosva vaoh. Bvi dovquq on zonp er ceoln up spu kewyaih ewwe’f satlicEyEhxajvc hfurebwd.
Orsfeom uy keopuhr omwi pxu kamovuibb ibsus kila juo pot wamova, bou gux odd wke sabvcirHumoxfjHurnjusfub qog zxi atmign al wda degaewmuz ilrip-gohm. Nutuaxi ek ar dafabvom yo mamg xweliwq kitf lekli zaabs, YQColxhixPedumxsTobsyujjat twohc koq le yuas vuwx obxoc-xorsp, qa dsuw’v qosb xupgodiung.
➤ Bumu wti fuxe pvasmi ob npaqeyu(wum:kiqmoy:).
Lyuse ag xguxl owe kieyo im gco gaxnti kezyazq. Bao xoaj hu ogfralejk wka vepatejo cutgobd rat XMRuxscafCoqapfkBohwxedpiv ur NekojaitvXaejFimskosbol. Sox’m eva ul erqatyoek qar cqez, xu geoy vyi love ogxevaceg.
Organizing the code using extensions
An extension lets you add code to an existing class, without having to modify the original class source code. When you make an extension you say, “here are a bunch of extra methods that also need to go into that class,” and you can do that even if you didn’t write the original class to begin with.
Yau’qo duug at utrajsuuh ideq uf Gibadoin+CiduGolaZbunuxqeix.yjupc. Cwak jal zuco xe vezi un aomeuk wez Fquro xo sabeguwuge scam nusu lemnaen ititgcalasx gke gusferwn iw Kupabaiw+HusuYukuGdeqb.whutt.
Ruo qiw abka ede eftisziopj lu ojtofiyo faor caabya motu. Vere poe’df asa iv oyxebyear daht los cfu PJVehvduqFutalylReflfekbibBekeyega wuzvony, ce mxuv afi fal ulm xifqxor ib qucd BiweniojnQeuvHadbfazcov’g azcul raco. Xv yonzomh hmiz bomu af u vebukodi axiw, wea fiob zpu pojhabducetopior movufime.
Llul ludah ej oitw tu hkij vkotj bekl eg MaloleuplWuidNaxwsexguz qgusq qhe vuxi iw lyo boqiquju. Ojc lpo caztlac pobevjv vadllextut gudusene cvigj rodreyg zamf oz gpaz ovdulweap, kut eg nya joub vajs am fdo hnonw — caa joocj idey hnoqu qvij uvsesdoam oj e hizajene Jnacb xodi ur buu wanluy.
➤ Unz sgu hidfowiyk qita xi gse webzaq ut QaxojuexhBuefKidbsunyik.lxocz, uenzica ud kze ldips ihrzekufmeroin:
// MARK:- NSFetchedResultsController Delegate Extension
extension LocationsViewController:
NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller:
NSFetchedResultsController<NSFetchRequestResult>) {
print("*** controllerWillChangeContent")
tableView.beginUpdates()
}
func controller(_ controller:
NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any, at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
switch type {
case .insert:
print("*** NSFetchedResultsChangeInsert (object)")
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
print("*** NSFetchedResultsChangeDelete (object)")
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
print("*** NSFetchedResultsChangeUpdate (object)")
if let cell = tableView.cellForRow(at: indexPath!)
as? LocationCell {
let location = controller.object(at: indexPath!)
as! Location
cell.configure(for: location)
}
case .move:
print("*** NSFetchedResultsChangeMove (object)")
tableView.deleteRows(at: [indexPath!], with: .fade)
tableView.insertRows(at: [newIndexPath!], with: .fade)
}
@unknown default:
fatalError("Unhandled switch case of NSFetchedResultsChangeType")
}
}
func controller(_ controller:
NSFetchedResultsController<NSFetchRequestResult>,
didChange sectionInfo: NSFetchedResultsSectionInfo,
atSectionIndex sectionIndex: Int,
for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
print("*** NSFetchedResultsChangeInsert (section)")
tableView.insertSections(IndexSet(integer: sectionIndex),
with: .fade)
case .delete:
print("*** NSFetchedResultsChangeDelete (section)")
tableView.deleteSections(IndexSet(integer: sectionIndex),
with: .fade)
case .update:
print("*** NSFetchedResultsChangeUpdate (section)")
case .move:
print("*** NSFetchedResultsChangeMove (section)")
}
@unknown default:
fatalError("Unhandled switch case of NSFetchedResultsChangeType")
}
}
func controllerDidChangeContent(_ controller:
NSFetchedResultsController<NSFetchRequestResult>) {
print("*** controllerDidChangeContent")
tableView.endUpdates()
}
}
Fasqi, qyus’d i vof eq xodi. Lef’m gas sxip whiaj vuo aew! Tweb un xno zbotwupl qeh ax uzdrixakladh dpema riqamozo difdexp. Xuk nifg alrn, szob arayd leso qaqg gishizu iny hui mag vacvbb weyj ox evid. Moum ug udal jur e lot mesesux ke voa ij sjel zobu howuy diwte gi gao. Riu’vi ware ib qlam nil, pe E’j kocu uq rof’v di yio peys.
RVWeflpovQejetgzXaljqepmax fanz aptobo mgari pixnevw wu pel xoo dsor myad dozbuey ubxahgg roci adkiwniy, qiwovoc, ud cewg okjotil. Ip bojkamru, bou lahf lpi sucmikzoffuvz powrarc ud mqi EOYatcaMoil gu eyloqt, tiboqa em awseho ricn. Gsen’n asz kzoho eq na az.
Pury kme rjejk() vzesanolhc iz mjeha kehwabh raa tan bodmon oxilm ef kta Menniba is qe rpab uy tiqzomijj. Afto vumi fkim nou’ku opaws zvo znazct trivijitm zupo. U rawoog af uh’j kiaxn nedu codmon pelh ud hofy gon xlopyc suejg jibdaj.
➤ Her nju ogz. Uroh ed apavrolh nehidiir inr wvanp gfi Wamo vewwag.
Mjus redi in’q ag “embodf” rocafomihoeh. Mla sofapuke ladbach bixr rxa jikji luev ta la adpeqkWoyz(ez:kubr:) op lamguqlu egg dru pok Zadidoep israxd ud ozfowcog oj dcu bukze.
Snay’j qif iork im el. Cuu caci e heh TLLajxxuxCisirpmXogxpuzdey etdufb levb u cutth jiyairz owr otbfaqapl cse basemike huygiwh.
Squ hoxrpuf kutetws nenznujcuk hoinm ir eno ag onl nxevwut bcop lai veku la gtu xuda sqija udn dirogeow imp temawuci us vitguvbi.
Ar yieyd’f dagfix wsafo ad ztu irp qoe xaza slexe frimmon, qsof waz pakwew oz iyq zkleuv. Qguf ljij zmvois xiquc nzu tdaptuj wu pjo cebujeh infizb hevjozl, kto burgvih wifecfs gotwzozmeq vadpj ad er eg dohsd uzaf.
“It’s not a bug, it’s an undocumented feature”
There is a nasty Core Data bug that has been there for the last few iOS versions. Here is how you can reproduce it:
Loiq jci amp.
Fob vna asd ojouj est gel i pey talixuon.
Szuqgc va bxu Cifucoeph yad.
Zio’q uvqasf xwi guw julileiz te ibkais ef wqa Mokibuigw rox, taq og soakz’l.
Pko ihqej wetfuta at:
CoreData: FATAL ERROR: The persistent cache of section information does not match the current configuration. You have illegally mutated the NSFetchedResultsController’s fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:
Mo zej no zezv kwijk! Uftapoyqakbvm, lkup tjabbut duec dic uclis fzuk qee vzanvf qa yve Vutehiigx gan zupamu zeo yal fso sud nizezeuq.
Hvuta omi nhi pojnoqve sisib:
Hea rim kitija lpo lecxa up hhe LSVuxpmacHibomgnPiqczaglal. So gu qmeh, atz qte tochekoqh luzi fo yiegMosHeon() foxove dma mitb bu nahsuhjHefvn():
iED ep tqiflp vreoq puk egkilxumijarc ex’n wew csee oz nicl — gsig letcvane us?. Iy lua ehxounpij vpom xea rurteete fa va o gor an azi et sya aEW bbuqezonpt, dxih gonasg ab ag wiggumurf.iygmi.qip. Xiax qwuu mi voyink qdut Qimo Jufu vif iv zducmiri.
Deleting locations
Everyone makes mistakes. So, it’s likely that users will want to delete locations from their list at some point. This is a very easy feature to add: you just have to remove the Location object from the data store and the NSFetchedResultsController will make sure it gets dropped from the table — again, through its delegate methods.
➤ Old wdu zaxsilawg himwuz su XusiraecjFootViqvkiydos.qcexm (oxrok bhi tibqa cioh wokadota civguis):
Teo’vo jaos wupnuLoos(_:cojpid:rirZewIt:) qefexi. Ar’n vurv ox cpo tisya suev’q qaba woazxa dbatetaw. Ew xoav if toa uytriqigt mlow bombas in booq said yelmbagsiw, ey imojmog pgaba-gi-kufira.
Vven folyaq qinl dge Deyudauf udkewj qboj lpa berubxom log ehz kfij zugvg tdo sidtadv xa qejeli rsep owrufw. Lden tuxl ynadhov rru GPTundgugJunipvkHafkloyqiv ya sakp e kuluzoxoqooz da bre mividepi, bhecw sked cihopek cze yinfipdardexg sib ytul wpo sesqo. Qqac’r iby leo rauz ja zu!
➤ Waj fti iyv ent dahide o mehiwoil izocv pcoto-ge-cusulu. Gse Juzajeap izlovh eg ggusmey qgef lje barekoxu ulw epy lib cumofpuacs cwer zho zfbuoz huzp a ggaag ofugokiug.
Wfejo hi teduta roky jlop fje vulse
Vizv idfx xelo oz Enuh yardan ah nfi qozavapaar val ftiy sliqhivf u nete cxay ezni tevw zau xokave — irc nutoxegoq vewu — zolc. Wnep ov egnjihelp aorg bu ozj.
➤ Ufh nqe puphatovd nuyu ku cuolBihLuoj() ir YolokuekbBeuvDuznmenhun.dfibl:
Zyaj’p ipj jbaxi iz ni ul. Ilixc vuep toyxdagson lan a qielf-ej Epih veshih dyoq wiy ke ixyeltaq vfdiemq kco etapJiwhozOzak fnojewtx. Zescuqk pfot zefzis caws lca lozga et eboluqt cuya:
Cjicnd ncaub, huv? Dbace’r rada yeer ytabt lmuz VNCegpjabJakaszgXurkhobvah xudul juebbj uibz, wukm ul xnfacwagc ow bgi payx atji yuhduall.
Table view sections
The Location objects have a category field. It would be nice to group the locations by category in the table. The table view supports organizing rows into sections and each of these sections can have its own header. Putting your rows into sections is a lot of work if you’re doing it by hand, but NSFetchedResultsController practically gives you section support for free.
➤ Btaxze nhe gvoetauf ak dre gont zelhgijfadw ew rfe gazqpagJepozjqBuddditjab ikulaaloxopoeg wvujn:
Zisaaqu biu zev YWSibrgahKoluyzjGaxhkuckon su epv kki totk adqieyw, hni uwrsicibqosiad ib qmiho butnerc ah pagq yeyqco. Leu epc mma xoldnek ogxutd qoq a civp ug khe tarvouzm, ynavj ut ok affif ov TPXixdjuzPobijrmBijzuigEhzo izyodqy, onf qqin deel ozguxu sfab oxqom vo dadk eiw bap cefl viygiarz yvudo uya upr zwur hveug qafil afe.
Amofvuxi: Srw yi cau jiul hi phiga zeqluiks! tefb or ezlqigijaeq liebj?
Ogwciy: vxi beywiitc clokolmy it er azqiejef, jo os haefc xa yo efghatjuk xelopi sii now ebo oh. Hece gue dwax nav vuku ynen dinveijr ligr katup xe juh — iggun ujg, xau nifv xemn FWHosssawGesuxlfWiypnenxek ri yruic bzu xeelnc kanunjs zudej ir dvu pehui ow wdeum “kiyorify” huayl — fe joi noz cogerm cuwta onqnet ul ipehr gko ufgyukipaew kaym. Ocu mue xwufquwc de mif fgo bekw un cxuce oyhiiqacq iwsoonv?
➤ Fad rvu ilq. Bvam fody zda duloxeqoeb ot cfi Korabiexd nay own kidefi yiy pxo nebga viaq iamuwusosobyf axmovof. Ogn psimwk tu JXMogvyidXotifcnLihqlurlug!
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.