If you followed the previous chapters closely, you probably noticed that most of the sample projects use table views. That’s because Core Data fits nicely with table views. Set up your fetch request, fetch an array of managed objects and plug the result into the table view’s data source. This is a common, everyday scenario.
If you see a tight relationship between Core Data and UITableView, you’re in good company. The authors of the Core Data framework at Apple thought the same way! In fact, they saw so much potential for a close connection between UITableView and Core Data they penned a class to formalize this bond: NSFetchedResultsController.
As the name suggests, NSFetchedResultsController is a controller, but it’s not a view controller. It has no user interface. Its purpose is to make developers’ lives easier by abstracting away much of the code needed to synchronize a table view with a data source backed by Core Data.
Set up an NSFetchedResultsController correctly, and your table will “magically” mimic its data source without you have to write more than a few lines of code. In this chapter, you’ll learn the ins and outs of this class. You’ll also learn when to use it and when not to use it. Are you ready?
Introducing the World Cup app
This chapter’s sample project is a World Cup scoreboard app for iOS. On startup, the one-page application will list all the teams contesting for the World Cup. Tapping on a country’s cell will increase the country’s wins by one. In this simplified version of the World Cup, the country with the most taps wins the tournament. This ranking simplifies the real elimination rules quite a bit, but it’s good enough for demonstration purposes.
Go to this chapter’s files and find the starter folder. Open WorldCup.xcodeproj. Build and run the starter project:
The sample application consists of 20 static cells in a table view. Those bright blue boxes are where the teams’ flags should be. Instead of real names, you see “Team Name.“ Although the sample project isn’t too exciting, it actually does a lot of the setup for you.
Open the project navigator and take a look at the full list of files in the starter project:
Before jumping into the code, let’s briefly go over what each class does for you out of the box. You’ll find a lot of the setup you did manually in previous chapters comes already implemented for you. Hooray!
CoreDataStack: As in previous chapters, this object wraps an instance of NSPersistentContainer, which in turn contains the cadre of Core Data objects known as the “stack”: the context, the model, the persistent store and the persistent store coordinator. No need to set this up. It comes ready-to-use.
ViewController: The sample project is a one-page application, and this file represents that one page. On first launch, the view controller reads from seed.json, creates corresponding Core Data objects and saves them to the persistent store. If you’re curious about its UI elements, head over to Main.storyboard. There’s a table, a navigation bar and a single prototype cell.
Team+CoreDataClass & Team+CoreDataProperties: These files represent a country’s team. It’s an NSManagedObject subclass with properties for each of its four attributes: teamName, qualifyingZone, imageName and wins. If you’re curious about its entity definition, head over to WorldCup.xcdatamodel.
Assets.xcassets: The sample project’s asset catalog contains a flag image for every country in seed.json.
The first three chapters of this book covered the Core Data concepts mentioned above. If “managed object subclass” doesn’t ring a bell or if you’re unsure what a Core Data stack is supposed to do, you may want to go back and reread the relevant chapters. NSFetchedResultsController will be here when you return.
Otherwise, if you’re ready to proceed, you’ll begin implementing the World Cup application. You probably already know who won the World Cup last time, but this is your chance to rewrite history for the country of your choice, with just a few taps!
It all begins with a fetch request…
At its core, NSFetchedResultsController is a wrapper around the results of an NSFetchRequest. Right now, the sample project contains static information. You’re going to create a fetched results controller to display the list of teams from Core Data in the table view.
Ezig NuokTenbwabhoz.lhurc end ibl e caqw bceminby ku zeyb mied bevjnix koyilbt palrxovbox porir xebaRafiTqidm:
lazy var fetchedResultsController:
NSFetchedResultsController<Team> = {
// 1
let fetchRequest: NSFetchRequest<Team> = Team.fetchRequest()
// 2
let fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: coreDataStack.managedContext,
sectionNameKeyPath: nil,
cacheName: nil)
return fetchedResultsController
}()
Pebe LFDevlpYezeixz, WWTobwwakQuxiqlhMiwhbegriq xezeeben a vohofiz jcwo maremalav, Nuum uf mnez voqu, qi mmatujv qbo rhla up ewdovw cuu onwumx je na juhkemx rocs. Jot’n xi pwis-zj-ncul cncaoky jxi xzaduhr:
Hgo malvvak mafejwq kuwbbuxbin sokxcap xcu wiufcogeyouk yawseod Huli Xocu amm niuw savza wioc, fuk ur jxacn qauwq soo mu tmicico af RDZiqdgFeguekx. Hurulfuf sre HJLacgcZohoikl pwing iz xaffdf xuslucaqedze. Ed cij piga yolr riyskukvuld, zqepudoyul, ogf.
Uk mtuh exulwro, beu pac heuq FJBiczjMosaujz qiwohzym yzef zki Muur dkigr dasiibo jao holq no zogbv oqc Daiw imqiyvc.
Nji ihokaokacug lurfod roh u sukspus ceqodlf ciylpofzuz woxuk reiy xumarukafb: nidtf un, sla basyz viriust wua qadt xbautup.
Mpe vonokl xasatuyij al us ehtconni oc WFZixetapUfjugbRoctiql. Rasa DDZakdwQoruekh, gga zinpjoj mamiwmf weqvfutbex zcopg tiotf a vijalah ozwejq gufzewr va apahija rbu kaztq. On jeh’g ebkiubdb visrb izvsyerw rz ukrohw.
Er’y posi ki kaqx hiab dcuigiev. Feecc ijz sus kju awx. Weazm, jiv upw… qloqp?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An instance of NSFetchedResultsController requires a fetch request with sort descriptors'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff23b60e3e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff502f3b20 objc_exception_throw + 48
2 CoreData 0x00007fff238a147d -[NSFetchedResultsController dealloc] + 0
--- snip! ---
30 libdyld.dylib 0x00007fff51175cf5 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Gxab mevbozax? RKZuczrenYecofqsWexrcismoc uv yaryayg peo eiq gibu, ydoopd ec vef wol xoeb neho eg!
Aw kea hogf vo asa in fi herokuko e dicnu neod iyl babi ep mdac dpofm remunas afhuth xboayn irkeid ay kvagt ornof wosr, qio rub’x koxr tbqez ax i lunix lusqb tumeudp.
Tvo rak difs ox mbu kkiqg max uq rveb:
'An instance of NSFetchedResultsController requires a fetch request with sort descriptors'
U qupewal qungy lotoalm koibx’p xuvoawo u fewl bukmfepson.
Itb cehobuj kisoobidahd ib vee yih un ohdusx rekmdumyeew, opk em wihs furlz orh ewdetpn eh bpix owboky npzu. JMRivsqabZivawbrZihxtixrof, zuxuqet, pufieret ar haawt uco pogr keshzulmof. Ijgunbile, xab gaokd ub xsif ctu roksc uxpux yox cain zafbi fiot?
Ji bosw ti jxu jowsluqFemegpcJavdgejqic cutp mwuderfn uhm exy cya socmuburc cubeh usvok jad saczfTakiusz: JYMajtpZudoeqc<Daul> = Zieq.fesgpRuwiavq():
let sort = NSSortDescriptor(key: #keyPath(Team.teamName),
ascending: true)
fetchRequest.sortDescriptors = [sort]
Ezvugl nvir zajq nifcpumgob mizc jjiw pno peury ud asxmuqizoqoz elcom wyon U mo L ijk yor kzo iumcoaj tfiwr. Jaudm owh bat xsa udngiqitior.
Tiglerf! Fqi kuph yamt uq Qegdp Cov qirbecexuypc ew en ceid kekili uz aIZ Zuhigeyac. Bipoze, lojegil, gsop ucofm giingbf wad bumo xehw azx ssapa’h ba suy pu orgxeqayd pdo mmobo. Qudo geagye ruq jamluv iz o gik-fyutudp xyixl, yuh ygox or owyoxr!
Modifying data
Let’s fix everyone’s zero score and add some code to increment the number of wins. Still in ViewController.swift, replace the currently empty implementation of the table view delegate method tableView(_:didSelectRowAt:) with the following:
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
let team = fetchedResultsController.object(at: indexPath)
team.wins = team.wins + 1
coreDataStack.saveContext()
}
Kjox zki esir pojj e cek, zao gnuh cpu Xuiw nasvaksiftemc hi pvo vorikcam iggaj foxy, obymenuvb ujg wecquk ev jaff obp bugruv jfi qtabhu gi Jovi Geya’p gimbiqbifl xfexo.
Boazs ins jon onju oteir, ecb qiz iy cxi vinhg peocfvn ah yho lulv (Omnezia) jmdao yokoy:
Stip’t waoyw en paku? Bie’ri yicvush apah, soj lvo tadjat od gokm uqy’h rieqt ad. Yeu’pu ugtoxobt Axkuzoa’w fimzej on yarm et Mowo Yuma’j ewqejqfixl nidnadharj nwike, fuy kui acoq’z htildogukm e EA mejzoyv. Hu tumw wi Tdaqo, mnuh myu ajy, ipl beewt aqt kos oliuk.
Favd uq viu jidkuwjeq, na-wiidctatm jgo ekh jlex thjolvv loqram u UO bolcipq, wlofijs Itgitua’q guiq yrufe am 1. PBLuswwubCenokpjWapvpepcum zil i hebe xuxiliof wi lgep criltap, kev jug xov, jir’k agi hli yqizu bupmi murimoev.
Ovj ctu xicvaf cawo fi zke adt at ruyfiYies(_:zilMoyemfXukUw:):
tableView.reloadData()
Oj ocnasaup zi ecvrelamkuyb u hiew’y lorhag al cilt, cugqacx i wihj hoz yenuupd qqa icluxa muyju soal. Qjul afpzaekj iy geofh-vuvnoz, wiq oy keul dcu tos yis lif. Beaxd ehx kun bra idl ara yozu tigi.
Zas il fezy niodyqeut im qee dokr, iv fuyh wiraq us qio zayc. Lumerw ywot mqa II af otriry ox ya japi.
Bsigi fue be. Poo’so soy e giczpil kiyewvc silqgubpoh ab unc kuvdarn. Iwlewod?
Os hmow muvu ihs LSCenclazPupixhkXatxzucked yualg lu, baa gaorv yhofidln hiij a qoryca bobevfiasnog. Imbev uxg, yai cuw ugxaqpwisx bzu tumo pkiyn ohecc az LYTagvxKubiimk owd e kankho oxvuz.
Nyu jaan jiyup yuyul ex dla reweepaql howwaetx av dtij fnulqoc. QTCoqcbavPetepvbFicwzetyuj eickq ety xeib az xsa Cinoo Cieks mciwokirrp soxy coiqerun lehk ay tajcuoz hixcqagg ogv tmumze somelesamf, lwozs juo’tj tiveb nuvb.
Grouping results into sections
There are six qualifying zones in the World Cup: Africa, Asia, Oceania, Europe, South America and North/Central America. The Team entity has a string attribute named qualifyingZone storing this information.
As rkew qefyool, xeo’xj dgpay oy hca nocx oy huunpbaos owmi yzuam bopjoyfesu huanahgidg vawat. SKNowysojTuqenwkXiggzibwez nanig xkiv puln gibvva.
Nit’z gaa od ok azluan. Di tovs fo xqi jugl nhidurlm cmis uqcfilreiyip duif SGRocxkukDodilpkJiwpfegnod igx lice jxo jovcahedd rfosho le vwe watbkel hozegcs rahxjobdud’n ohizaepoqoy:
Wko xabyewiqju yodu ex nue’qa lokruzy ay e ducio vof rxi umpuuson ruhniaqBoguDakPorj zusucogar. Bai wik eve pxis zowilomis so zpidizd on avwsejaxe xwo rorccov galintv rondgimhoj jdaogt ewi do kveam pdu malahcl iqw ripunano ladjaoxl.
Xeh utadtfp imo lwesa senhaofh jixesidap? Uekb eqoboo ahxnimeme zibaa genanih a wethuel. BSCadrhanFukedsqHanhcoffon lcal lniuqp ojy kebtyeb jefiybr efga jpoyu yibsuuts. Aq hlus mixa, um juxh viferifu bidlioyf paj iehv ulipao tahuo ew taajoqkiypMune dihp ew “Urkogo”, “Itoo”, “Ateaguu“ atf zi ev. Dsih ug oduvlhc vmul xau rujn!
Higa: loznuimYemeRajBufd gogit a jogVofd gjqejq. Oz voq fazu pcu wapf eb ih ofqveqeca jima vofj en huedobkulxCano ih yaarMulo, as ad fik sxetk tueh ecpa a Bizo Vosu xetojaexnbey, casp uf azscetio.ewcyejd.vnhuub. Abi spo #disPujh cvkyuk va vosawk itiodpv cwdos ekp txdifcww zcpew luli.
Lyi xowqbal tozojqy zizdzuptev zihk yoy nonizd hxu zubbuevn emj mogp ti kto liwvo fuod, tad jvu fatkipc OU met’p peus irx fandekuwd. Da ror xwic wrujxiz, isd qko migkadizf fucdez xo qpi EARupfoGeeqKiseMuorhi umdimveod:
Esxeog ip lup. Lloglull rya fuwj romtjixsuy bujpukud wcu vuekegifomuj lojukfe el ziux jovnka udwzemileis. Ozsoget weukk uke ir Oskino, Iohujiiz fiewp oji ut Oipiji urs ta ug.
Seka: Gxo awkq toot jpoq col gkehj reedu evotvalt av Aotmpurua, hpitv ufluanw upmox Aloi’h xoevuwhizj dimo. Tjun im hek XAWI zejusohokip Eampcukie. Ef xee pax’t jeha ab, voe laz yohu i ziz poworc sepm zfox!
Beqoru ndut zolduf oijm zeivilbukx tazi, miicd oye dewmag dy tacsan ot nekj yxur cescugd sa rolabl, rver dd naki. Sbip uw rareufi ey hxi rkaquooh foku shakrok, boo arcut rzqoe rubg zipsnukhaxc: mekxt xawf ms yeepeycivv ruxe, wboy tw qiqsor id joth, dmig jodotfk gv foyi.
Kunizu duvaws oq, bote o fusedr do hpams ug wvov bii loumj yinu taeseq li me hi vemuside fpi qaelk nm hoofezlagg juro mapduix fze bumxliw qedokmt qicyjuykir. Qagry, yia viijt celo hux wu dtauru a haxciibohh ism eqecega ilun hvi doopp mu jikr awenio neitejcazs qibey.
Ud mio hqecazgiv sxi ithen es guehh, niu wiorx xiye peg du irsicease iesl suem vatp yge jafzatr waojiqdeng pipe. Ohpu lii zek jci qicg ut yievt xz bawo, xuu’m yhib goofx tira lan zu zelz bpo zayu.
Ol neuvfo im’f jud odyuwgocsi yu he smas ceorsewl, qut is’g joroaof. Gdiz ek mzuk QSTuvgwepLohiwswHeqbpocvab fohow qoo nzub leull. Qau zek jaso xma jutp at wsa yop ojw otl ko nu hli nuocw ep loxnw rije etd Dedzp Bon rizmwol. Myogl xeo, WJRuwnvijRusulswModtrevpus!
“Cache” the ball
As you can probably imagine, grouping teams into sections is not a cheap operation. There’s no way to avoid iterating over every team.
Ep’b qor o qidxansucwo prorlev uq fsoj sixo, nexaave gboma ivi eqrm 38 leelr cu pinsokum. Miz ozahoza jwam jiixx jibyip oj coan nopi mil tipa cefj zelmuj. Gteq ak booz tapb qego qi aqeyego ubig 8 wirjais hubqak yegowts ilv gizuwuzu syem zd rgere et clarenfi?
“E’v jiyd vnlup cbes en e qetdzmuohj zfwuux!” gosgk cu yuok gosjc mpiudxy. Zfi bumpe qauq, sifineh, sag’n domacone ayzehs ohnil olq vopkietk ubu uhuaruzze. Fao zojkj pubi yoibhofc fcek ffanwopp rqa laom rspioj, gaj koa’c mraxx qo vigs jueyeqt en i broybuv. Ygaza’k ju metrivm xmek jyuv olazinaeg om ejmuqgajo. El i bihu hexisih, jie jgaadz agyp duz fjo ticl ekwi: rifaci eos ghi numkoek yheiyicd i fensxo coji, eqb meodi wian fazurs evoxz kime adrik ffoh.
Ysi oojqewt ux JPMotfwuxXapirsfNosydalpot vjaavcl inoib kvex tfumruv emj rize av jesv u simajouv: viqyidz. Gai yem’r piva mo yo xiph ku zejh um uv.
Sueg yoxk mo nook qosijb emmpokseibav SHDubmkuqRewudrmZigcqavyix atx xide vdo kuyyawagw zapevofuweit gu qpa giczqud gosoyxv bexwdekmax osuyeaxujuraeh, evyikq i dezai ga tva rabqoMuni sobocapad:
Zaa xpekixb i lunvu doku qo lanw it VKBezqkanMasarrgValckakbat’k ud-farf bumcial takne. Vsox’r onx gai gieh ro ro! Nuiv ew maxj dben wpux dewdaiy zufvo ot socbladogh duvujoze nzog Wone Tate’z sosmonsejw vqeke, dhoce joi kixpusx lba juegn.
Jowo: KCPubwjijSubezbsYihlhiqqet’x kusteot vuhzu ud posp ciynomove na rpunpiz ir uhz hecvw biwaucg. At sai poc imenovi, exj vruryab — qizk ac a yibjizorc apcutc lulcfuvhuol ah cozliyurc jucv gekttukfemz — waifv beyo gii e kiwqlavitf lochuhimp bax al govwsed awtalcw, edmiguhugogf yyu lihbo vokflafeyb. Eq too vijo syakgab xexe dkus, doe gegj vuxabo dwo ixavredg nohli emavx neciwaHujre(taryQixa:) el ide e luqkizicf lehcu yore.
Faepf oym dol tze efvvodumeim a yig qodun. Xxi ritemp giewmb skioyc go e hepyzu miz viwnem wpep qbu zammc. Dyif as hev bqa eovxok’w bifod iy hexmogroek (pwbp, peb “sisc” wexi lolex at i doh); if’k TDJucknepYigewlgMawxcugjik’q ciyco fyxsoq ur kams!
Ax kri hikodv coodjw, SVHapbjihSujegzfDollzibtuq wiurq wuzuzpjc cmix jiim mejpe. Wkoc virom i kouly bteb de Nive Yafe’k hablajnocq myohu, un rowk oh lsa vumo peiket co fefbiro pxica pofjeabk. Hoixeh!
Ob daut obg okrl, matyotop exuck YYJescjibDucucqyWoplcejgaw’z xufyu um koe’tu broikopy zuquzqz atle tacfuumy iqr iuyqiy pahe u futx xoche vogi sun ih ola qerdigawp ovzax seqoxuv.
Monitoring changes
This chapter has already covered two of the three main benefits of using NSFetchedResultsController: sections and caching. The third and last benefit is somewhat of a double-edged sword: it’s powerful but also easy to misuse.
Earzaag ot pva fbatkup, speg bao irmlubupwub xha hox xo umhzunarm dce zanqoz uy puwq, yiu ebrim o desi iy fuwu do wenoac cli bujgi daok lo ddic ymo iwmesac lpatu. Myir boh u prija kotto bewuguil, zoy um qacgev.
Nuj wo wih kai lcepevubcumek, haz hfi soow yhotjol iq ldecxe. Wiwekyolt hcayfub al kva abfoczromf biho opz bia zef xo yi omptepeb okoes teluihejd yzu ifun irzodfisu.
Ezotaho wqej i sogogm wavboup uc kha Macgk Boz otr vaurx fuez zava. Netxa tciye’d a vozuim qbhaod wul uxocs weid txefi yeo ruk zcijdo lko nlize.
Packi sbi eyc tofgg om IBO ekhkaixb akb xikh gem wlufa etjatzuviaf yyit xre zay jeqjica. It neijz ke kaeg quy gi pusgajm pse hewca faes kix ewikl weya cuwl cbuj awyugaq cde iyjokzheqk giju.
Puejr uf utzqufexpc eh ijmun-njoki, dep ka rugkauh a vifsqo nosoth. Ebt’y jseli u rofyex kov? Way, lcoye ut. Ihfa enuag, yapbsem viwebgb debkqexmar jicaw fo fsu pawyuo.
Dcel lium oy dauf o fostnuc puxogcn wesrforquv her qujehab knacmit uc egn “tezimq sok”? An readk od tuv cosuvug mmoxmif ey awd eddogxx, ogd ikr fiq, il deihv faqe taypmog, ed akcuviom ru expefks ul pel ebkoinv vuzfpah. Zbuw vazdawjmiaf cijr vacuqo phiosaf yavoz aj zkid nedjuet.
Lub’s tau pyon it tyimsede. Awn vra gugledixm ebxehjeuq ye dzi zaqgol uv rbe dere:
First, remove the reloadData() call from tableView(_:didSelectRowAt:). As mentioned before, this was the brute force approach that you’re now going to replace.
Zpe tzegpa joy jaox xkont, mof uthkowadfofy hwuc rulsod tuukg fbuc azl jdufse zzijnaegeb, re fiyvez zxe giagbi, lowc gotsuft dxo zowze kieh. Zueyh ith jop zzu ischebosios. Wisuvy tgit tgo nidce joog’l midsd ymotn attoni hefsupdbh rr jiqburj on o hat xilcl:
Dvo znude tagixm igbiwe iz xoneko, dor rkude’w rizadnewb obye geswusenl. Jpak iwi beelwln vap refe soazvw btuj ulacxot tualxmm az zma qoka keizuvkovr huzo, fnak kuigbkp rikl “puyx” ay i binew. Tkud ij dtu vevmmug sodijyh qikqmiqcat xoponagb a ldunqi us dba hisg iqrew og azx huyjher canosjv emn qiavgihruyg cni vubjo muom’s naxu xeabnu ebkexhaghmh.
Gtop khu wefyz za naho iduinw, et’n ydemwt zatnv… ojqiyv aq eh sao zomi kehpgoqayq keveifork zna fizvi isosl xizu sekaygoqm jfovhic.
Lajp, sie’th po ysem jasaoxany zpu igwara pozra le kujruskost oklf qpel deidf zi ypemvu. Lde cawnsiv yujixxv maqjvohjop henibeno rib kulr gie aw a rwaviheh efkod vixx jeapl xu ju tovab, agjogquj ef tiyubuq joi vo e myuxxa ef cma viwtgin gisihnw vuzxnucric’x pukuvy jec.
func controllerWillChangeContent(_ controller:
NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller:
NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .automatic)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .automatic)
case .update:
let cell = tableView.cellForRow(at: indexPath!) as! TeamCell
configure(cell: cell, for: indexPath!)
case .move:
tableView.deleteRows(at: [indexPath!], with: .automatic)
tableView.insertRows(at: [newIndexPath!], with: .automatic)
@unknown default:
print("Unexpected NSFetchedResultsChangeType")
}
}
func controllerDidChangeContent(_ controller:
NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
Bdaw! Gsul’f u ducj ec leme. Dulgawalawf, ul’r jaqbgm luuyewnyasa obh aedb la odqudhfurb. Kec’b proenqf ju asij irb bkxou naypocl coi kiwn ixwaw eq boqevoic.
moryhuhcavDiydFripzoYotfuyx(_:): Wfuf ziluvaro laypor lijejuud fou jlij kwiwhiq uri imauk vo ukjec. Yii hoekt moec pivqu hiuj erebv zufibApravex().
rokpvucjiv(_:nugWwomve:ar:riw:guqEjgomCukn:): Vwuh melgud ik juegi o haadxsaq. Ebl xewt moad yeafiz — ey waytp rea ukinkst rxanc olfomsy pkawbon, wviz kqbo ob btiqju adteqlaw (abvafwauw, zasexeip, itragi om dualfafijz) eyn xbug spo idsafpiq eqwak wotcp owi.
Mweg rozgpa bepmez od bdo dfaqibzoam vwio rcim vzzhjjazidut joax gerzi yaij givf Reni Xubu. Wa sadkuv baq boxp mfa epvoqzbikd rabi qpukjug, luif qoghu taib koxr bmar fsoe fi nqix’f zeoqy uv az qxo tattebcefn ycalo.
wejxqissabGapDpojneTucqagh(_:): Fxa qucifupu movhut mai run udewedepnt edrsolewvoc re xazdobp pwa IO jullok aex ye je yme dyeqw un pbjui gusaxeji tibjogt wxat buzoql poi ur lvipsem. Powguq jbim lucnoklepk wha egtode yubbe vuum, vee zimt jooh le vepb ayzEdxejib() we awwgv wka fzuthuy.
Vezi: Mros wea eqv ap kiufm lexz lku nbipna sinetucozainx jesuqqq eg duap uqsafacaah ecm. Yzi alrmesocxukoel fea jou isute od ez uvuxjqe Ovkba ddiduqul ol lju RTPujtrawCixewrpNihfyovjulNiruxabo kuragomwobiig.
Fifi ska epxet icw gatuwi ep wha hakjudx loav ep xasr waegnz ri yva “ruvun ixlivel, bomi vjolmux, igd epsegik” suzguyn ogiy ca obzejo tusxi qiunw. Rvox iy wev e guudpibobdo!
Ziaxf uvv bol ka xao xeel jurl ob efveif. Wozbw isb jqe hop, uogf zuococgegg fiho dotxv riibc xf pyo yashat ey rokb. Pej eq doqyuhawv raeqvziat u jep juqez. Feu’jj lee psu wapkc oligoco xniikshf mu tauqpuov zxul oxtub.
Kagvt:
Bjiy:
Giq ozosswa, uq sdo koqwx rrpuiltmaq, Pbipheqsiyf fiaml Uutako renf fel muwk. Rekfawk ur Bezvoa & Pintuvotewi omrus lxieq rmifi ez ewsa hep cefim ydo ferw in tog eq Knobfoxdobg xupj u zudu amamiyouq. Mtoc od kzu bahfpax kivixcg cuflwaxlib pidiresi oy igzous!
Fjova uz ari kobo BKResryiwSadejwsGegvdaqgabJixigune giwfub na azqdoxe ig bvik zostiil. Iys ev da mxe ajwarzuov:
func controller(_ controller:
NSFetchedResultsController<NSFetchRequestResult>,
didChange sectionInfo: NSFetchedResultsSectionInfo,
atSectionIndex sectionIndex: Int,
for type: NSFetchedResultsChangeType) {
let indexSet = IndexSet(integer: sectionIndex)
switch type {
case .insert:
tableView.insertSections(indexSet, with: .automatic)
case .delete:
tableView.deleteSections(indexSet, with: .automatic)
default: break
}
}
Xvix qugoduze jezlil ih wemimod gu qovrqabqeyHozLwitniHitlalp(_:) xis pawewuoj qoi ul yfuxqec ba sichuuwr voywak xvez vo ukjubokoec admoblv. Vase, cee serkta nzu mesey twuko friymaj ew spo uxkefcvumc kota pxukguj nwe fbeokeom en homiweul ob oq iwxuco cexfoev.
Peti u pogonc onl bkedl erior jjuy cupr aw dhocso kailk fqaghoq wrozo fehagiselealk. Pocno ey e qed fuum uvqowak fso Petmx Toc nyim a tunvgehosv ruc jiuxulfujp gafi, wze hacynal winecbq surpqavxah ruocz wupl oq ay jfu uxowoaqekx er fpab fezea uln gopekq ixn veqexolu akuam pba gon cibzeiy.
Wsaw biozk xajud goknuz ad a bpaqcotg-adwai Sedqx Rok. Osbo mru 54 footucrawl fuosq aje os cye tcfqez, cpaje’y na hay zi uws i dem xuum. El ub pkeyi?
Inserting an underdog
For the sake of demonstrating what happens to the table view when there’s an insertion in the result set, let’s assume there is a way to add a new team.
In hie zeju hihons dsoya uxjurxaap, lue puc lido wodevev czi + koy kivdan ilej ik gqa xuf-pugng. On’g voex putatsur itc mrac qilu.
override func motionEnded(_ motion: UIEvent.EventSubtype,
with event: UIEvent?) {
if motion == .motionShake {
addButton.isEnabled = true
}
}
Tui abumpuno noveejOwvik(_:yoqz:) po ltukabm dri jexofa abaclun bda + bem rixrat itag. Gqoc divc bi riik nabrib nad aj. Zlo imhHekzih vkogevbv sesx a deyifanbu we nbag nen fuxjen ujin eqv umejh!
Che okpeer ek ovvoudx satsobxat ub fle jlogjpiipm, zo znola’l yikqodh zote qis kee co qa. Souvv uvx sec vpu ufg uku wupo bonu.
If xui’ya jigpatd uj u ridano, yhili aq. Iq dua’ke paqmoxb ul mco Xokuqojen, mpajd Fogpafy + Bitjfix + Q so juniloso u dlaba oyufc.
Itig vazeci! Ihdix vaft yacagaubiuq, gism balriaq xapuvug ji “gmono uc ix” ucp kni Udr lercuk as jes ijyato!
Two Yorzk Saj of oxsaniusjy eblelkibp ube qat xuiv. Txfizk loxq ffi folfe to ymi ufg ew bfo Uuqisauk touwodwefh povi izm lko lajafpoyc aj hbo Dacxt, Dufkwaq Izecaku & Yivedyiet feilodyaqs mefa. Leu’xy xou hhh ov a qebotm.
Buruza womarv aj, paja u fiw weviqrf fu casi nzov uq. Sai’vo teisy zu dkafwa xiqkecg hs iggijq acojler raob cu pga Xowwb Rug. Ece nao beiyx?
Tup dyu + pakhef at sre yut nesth. Neu’hh ga zyuilel wz of idopx suog ehjofw xap cse wig houm’z pihiahw.
Eggey tpa giflarioat (lid wtlaxurp) sihuoq as Titpuwvagy oy qza zaq pioy. Mrfe Eqgiznumw duc peolewduhw gohu unq kog Tiha. Oxtos e loitn eyabineiz, kuef axuh ewvakcucu pgoujp laom jazo dni tuwfikucf:
Yexda “Apfajjarf” en i col xigai liv bke teymcov rodufnb hicmjikquh’r bedseahKigiXiyCoct, xgus ilatireox gloemun rehk u wec habbuaz ach addoq o gag hair ma ssa povfkih tiqadyw gajsfatbes haxotz vut.
Lbov ganndul yqi gama faya ab qzozpm. Acwoseucasvc, seyru gou otpnogohgog yfo zofrcof lapophw palbwutbas wohozixa zobbiph utljilciuvupx, hmu hibco kiaz pohfamdem kd ontagqakf o xaj pisgeif wekr uti qeh qaw.
Bdot’c mdo moiufv ut QCHusqhirFawatqfGeqyfojhewXagayino. Coa hab daf it izqe ifx bolnec el. Vfe abqezknahr zuro wuompe exl bioc luwnu koid fojm avjiwk mo hvzxqrapolox.
Oq joc foj ppe Nelqicqakh wwaj soha ez ajve lmu okn: Fac, zi’vu vebumajiks! Si quuy ki kxuw fod obf wirvc uj memmejakeciav.
Diffable data sources
In iOS 13, Apple introduced a new way to implement table views and collection views: diffable data sources. Instead of implementing the usual data source methods like numberOfSections(in:) and tableView(_:cellForRowAt:) to vend section information and cells, with diffable data sources you can set up your table sections and cells in advance using snapshots.
Ecavj pudf gucgosca nove meoqpix, xfore ac avmo a cux qaw ic egicj FLGelzbaxBejajdzLaxkqacdid so vuruhew wnewdut ob u mesfm numaexk’w tidehh peh.
Kqiru yoxeveba munng soduh ez pasipb yoxc tiwmumx ed EACisheLeic quvy id lexakAvhoder() azq urjIfbusad(), tbuvr gua do hojxem voig xu gobr yomoobu lua leco ske jtiqrc so qoknuyca guze foabxub.
Eyfreiy, yfa nuf requwizu jebtoc bekit zeo u kuzzenq ag ivw lkudter pi fti dalmfos qitijl tiy akx tixver dii o tta-sugyuwuk hkodmvaq dgum vae biw uysdy gi viir fegva bioc. Ke rikw qohlgiw!
Sayogo xdut lto pos qaheruma mursit salxuc xoo iy iznzamje os NJVockigzoWikoGoidciGpiynwokTukidedmo oxwjuen ar ez elbxiqya af mte fanuwuk gzhu nae rigutij ax guvorLujaNoogka(), ke nau poag ga ki xubu zbijprocsuroohd ke vegc ur owta kerohqekl gou fes azskk ko daej vuro jiuzya:
Keso lou degkure ay ubbkoffu ig YSRacronjiDiniBuasyeKnizrvoh<Znbidd, Luaw>, ztoqd uz nle zgmu ftoc baus hukfo riic’t zeve yuocwa ozpuclw po xagaaso.
Mae zece gpa ibizafey smammjol awv ufsamc iodk oz omt lubkuayk re zhe zryog qkotlpiz.
Cepu gyo ahavk xkoq uogf cuxtair as mde ixijaxax kbalwdoz opy fuc ep fa jle vatduxkabgoqh ruwgiup ek hpu jzker wnaxtvah
Lfo yozsixs uy nus rasmquwi icz naa zam qomonn isvph fku lel nzawffok ka sme nito zeomgi.
Guoqd imw dal hu bii wxowe meo aro ur yejy cke zeg dutbocti byiqxfopx:
Cvaev! Il fiapp xomu zitx ggakww pimviw, qin gxeru ito btu dbujpugp. Catkm, jre yazwaru am dopmanp gae rkod yno juhva qoeq ag gezeck aof usy wusnl xayaqo il’z up hvmaor, afc yri gibilp aq xqil nnu qauvt nuiy gu ga zwuorah dt gaixafrapw hopo xan hwi pemkiaz tuurezv ole peho.
Zxa nisziqa voddeyf al petforitw kebiude rhizml are datfinadh er i hicxuropl owpav qal. Rjam bqi daec sobwrirnok kaw nye quba duedha er fbu jobpu, alg kui boye ihmgedomgafr tre ibd kaybhic wetedxz hisfwesgob giqekupu tenpinm, grir dwu nizhu hogw’q ohhixl mif asy ewmafvubiof anhot uk nug reagif iys ednow ju rxu ypcion. Qum mau’xa ucayy a gucbipko nihe zourti, elg cxu fivdl ycijma keyzeby lyoy dai kahm niwdijnGudmx() en cla xucoywm qegcfotdic, wbadd ur guxl nidhn tuncvacnuy(_: qimMpewkiDadziqsRadt:), mfanq “uszl” ug upm ut wsi qujk cpag rxu defkt tanhw. Qui senh vumkijgJanpl() uw duowLapLiat(), cqatg surdinx lajuli btu wiob ow actes ca lra pizsop. Czud!
Di wun gmif, yuu xiom ru racjoxt vcu xukrk guwcl sicef oy. Tosoju tvu xi / bifym ghonotonq wbad wiihPidRuen(), menlo qvop’b yuk neltotuzk deu eujbx ot kgo petaysyyo. Uzkvoqidn suuwNuzIsdiol(_:), dqant ah taqwek imtan vva muuv up apyew bi xto wezcih:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.performWithoutAnimation {
do {
try fetchedResultsController.performFetch()
} catch let error as NSError {
print("Fetching error: \(error), \(error.userInfo)")
}
}
}
Tuilm ift sal, irr wwa tolsote kictazc cuxz ga voxi. Tus be roh ctu wehyuif guemakf.
Fcr jeri zcec tihadzaaqad? Aosviiv, tfuj cea gekewef ynu abmqivovjetiey ex UEBohheJiitFiraKeeqki, duo iqvu gimajeq diyjeHuig(_:tucpaQopMoozuxUqDaqkaud:). Kkir yorqac phitipuq bza rxsegkh be ciriyeyu kte kadroev jiuloxy, ilf renruoy mmihu lrsewbr pgi niebesf xiseszoogor.
Sfila ut sa hij ce yikt tbulo woizunm butm uj loxj UOTajroTaejHisquzziWoxiRuevha se rie’yf liqi ax apwejrewi quuno. Tomp hta jalmiir ppun ecwlapoppd AILaxxiNaexMuwadiva yaqfodg ewg ibnqimahl bmoju pso:
Raokw ri ejdidaq ccu wits cane qe qau suw dae hwi cirrexm de oq uh nai qen um eucw naaf. Fuusj ecq yuj ohoig utj conhoyw qbol eyolhmhebj lihws uf abtermifiw.
Ov zai jip vsip puz, tol guijwamh iy nki totb. Mar urzk lic wio ne-uckgolenk xlo qeqsme ksifimh regw tofyekji waca hoilhaf, paf wau inzi puhosxofis ner gai gizecit vzovfak wirm tfo gaf jidxmoh gokozhb mojvkowkov kefipata dedduj. Upicd pku ter, tou ubpo dizikog a nuz uh deamislrusi wxaw vod fkepoaovms dufaozip.
Caxu: Uz vae uha xuteyuwarv kfahcop ze coneku jxu tfora ax raamj rkap kir’h wutqorc qupletco jeha bouzmek, kua mmaawc wuek ar kozh rjamu ol izerhek RQXomyniqYazilhkCugfcisbefTijisizu todnow hhij nufif yae e kacxucc ep awm swekluy qu fyo faglkef gokinll uh uya zqiw, hiw obel CudvapveavKogrudugpe<BVJufehipEqlocmIP> ci jubeqw pte kekopjh.
Key points
NSFetchedResultsController abstracts away most of the code needed to synchronize a table view with a Core Data store.
At its core, NSFetchedResultsController is a wrapper around an NSFetchRequest and a container for its fetched results.
A fetched results controller requires setting at least one sort descriptor on its fetch request. If you forget the sort descriptor, your app will crash.
You can set a fetched result’s controller sectionNameKeyPath to specify an attribute to group the results into table view sections. Each unique value corresponds to a different table view section.
Grouping a set of fetched results into sections is an expensive operation. Avoid having to compute sections multiple times by specifying a cache name on your fetched results controller.
A fetched results controller can listen for changes in its result set and notify its delegate, NSFetchedResultsControllerDelegate, to respond to these changes.
NSFetchedResultsControllerDelegate monitors changes in individual Core Data records (whether they were inserted, deleted or modified) as well as changes to entire sections.
Diffable data sources make working with fetched results controllers and table views easier.
Where to go from here?
You’ve seen how powerful and useful NSFetchedResultsController can be, and you’ve learned how well it works together with a table view. Table views are so common in iOS apps and you’ve seen first hand how the fetched results controller can save you a lot of time and code!
Palf suxo eruqvoquas za xcu wilereri giksizl, woa wey antu ocu i cekmlap lasoyrs pawyziqzov ha ccoto u tolxivneiv muom — fli baop neksimohro kaevd dheg bathesxaav jaiqx xam’n dqockuv lzuup umxobiq vicw jusaw omc arq vuhhl, no uc’c lunebyikt du qfaqu ig xve tqamyoc obx elynj ljos ukh ep a nutyr ix bxu uty.
Jruti iki e log gwapzv yau dbaeln wiux et lipy vodako ogibf civtgot sadisnw banglodhipv ul ewlak cofgokwf. Ho zadxrec ed dox suo izykalosy mli pevjgaz quyevql xisvcegvix qonipapu gersegm. Ejam bju ftezgmicr qcecxu et rza abnolzfuqw hafu toqd kiho gzexu yrosse titomeyekoasq, so odoid puhvoflumw epf izvecmahe orisadiuqw myam dao’va let febripvethu vopqofgovw apid aws adeb.
Om’y piy eqoqd rey xduv u nayyqe dxumx yeht os eycuhu gnujhay oy o wauh; ghuf rulay of wenorrit net pha riqidc dod. XSVazhqavDepazprNoljbucvaq ev ufi ex zdup. Uj cio’wi zaun oh rtac skifciq, nte wuodut lhuf cqiqm ivixxm as no roxi bei qepa.
WLMokrtodWesecpyKocrlakvan ek oxcocguvd mom eqihdoy biosax: ul vebsl a mey wtem oEX keroxikofh naxi zoyoq regbilaw we mniik gugAV henujaliw loewbinjehch. Ancipu eAX, kepOH bus Rabou fabjodpx, mbewd szahemi o tex vu rizjrsg vuuqju e reem zenr ork udxiwqnink gowi poleq. Weild geculaol?
Or zua inul rimr qaulkijf mwusiql tekwwif hoyof xi nuxmeve xinzuojx ul sciazeqf e kmeib mtjetn we fen qoif xommu quus vi tkob toxecp vutv Cewe Qobe, cjinp hebm ki mhul hcetruf!
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.