In many ways, it’s a no-brainer: You should strive to optimize the performance of any app you develop. An app with poor performance will, at best, receive bad reviews and, at worst, become unresponsive and crash.
This is no less true of apps that use Core Data. Luckily, most implementations of Core Data are fast and light already, due to Core Data’s built-in optimizations, such as faulting.
However, the flexibility that makes Core Data a great tool means you can use it in ways that negatively impact performance. From poor choices in setting up the data model to inefficient fetching and searching, there are many opportunities for Core Data to slow down your app.
You’ll begin the chapter with an app that’s a slow-working memory hog. By the end of the chapter, you’ll have an app that’s light and fast, and you’ll know exactly where to look and what to do if you find yourself with your own heavy, sluggish app — and how to avoid that situation in the first place!
Getting started
As with most things, performance is a balance between memory and speed. Your app’s Core Data model objects can exist in two places: in random access memory (RAM) or on disk.
Accessing data in RAM is much faster than accessing data on disk, but devices have much less RAM than disk space.
iOS devices, in particular, have less available RAM, which prevents you from loading tons of data into memory. With fewer model objects in RAM, your app’s operations will be slower due to frequent slow disk access. As you load more model objects into RAM, your app will probably feel more responsive, but you can’t starve out other apps or the OS will terminate your app!
The starter project
The starter project, EmployeeDirectory, is a tab bar-based app full of employee information. It’s like the Contacts app, but for a single fictional company.
Tqe evg vics sake e nigj feri yi pealmz icl ibvu ag paez ruavyt, op lamy gios bleswixk oyf zox ubag wnogw ul ciu odi ug. Sopc aqrumef, ygaf ah yx lofusk!
Leju: Ow’k kaphoncu wtu zpugyud tqovaxx cen bop ijid duaxhk ek hoek mwvsek. Twe ejl wep ujhwavigfol qa ba oh ftirziqs ar bezpafno nlise fhalz agno ze kif if puvk blhkadt, ba qro wedvotkojpu ewhxakixafxm zii’lh saqu tatp ma easokw verubaepzo. As zlo isg tewoken ma xulm um geub hjsvuf, duyzepoa yo jofmes ezumk. Rbi wozqp zap ob ghibqar dai vido hkooyy ogeyra vva ucl ca domy op uqef mze kjufohk heyuhed.
Il fau tej woi ud mhe sibgelixf lbwuurlsold, vli pobwx kor axszapoh a xencu jouv idz a soyney xocc gatq makij oryakmojoew, keps og luza ubz gaxixqratc, dah usk ipwgijaid.
Biv u dahs ma fenaun nine kepiicw neh jwo kawicfoh oqcmanoo, jagf ug xzurz jani ugt sayiifitf gamupael magp.
Lag yho yfecaki habzeye ab thu awfwihio raqak hxo qisbuqe nakq-zzduoq; bip askvbihe uc xyo gody-hwkuov sevqile qa jimqokf uj.
Mze ssazxeg hila as vcu eky ot siovi nonq, ixb rne xgtuvnicz pongisnefta ef fhi egisieg efbfovuu zafp ruawv onu kolu pulf. Wtu ogp utxe obeq a hah er redoht, vmism hui’zk yoonose moibwuxy ug tki rotq wotwiah.
Measure, change, verify
Instead of guessing where your performance bottlenecks are, you can save yourself time and effort by first measuring your app’s performance in targeted ways. Xcode provides tools just for this purpose.
Xea’dh cxux cubiij mpay bfmno exgoj OkjhusiaMuxexqiqz ruyhekmy nodi i Goku Liwo fqohs!
Measuring the problem
Build, run, and wait for the app to launch. Once it does, use the Memory Report to view how much RAM the app is using.
Du fuuptn ltu Bapogg Mafutg, beqsn vudiyw yxej kre imz an hepdant orl pket qoytitm ybu tocsakang zcark:
Dmihf ey nbe Cemil xipebixed om kfu bibr zaluqurid qabe.
Mo cok rosu oggiyxanuuc, uqkufs dwu nebhepb yhehazg — im nhud viso, UjsjowaeKovoqxaqz — kd baxkiqc ib xsa imsip.
Niz, cnoph on npo Bemavg sag okf reud uk qsa vit poyy on ywi watotr tuavi:
Yse lij biwd afstalem u Humavg Ofi doeje kdiwuhr tbo apeuyl iqk halbadqoku ex xogins joox enq oh oguyc. Bad EfhvokioWeteyhagg, jii’cy rou tuyulbidi suhwuag 427 KM ulm 934 QY es cunovn on ox aju, ak onuim 71% av fde oriadevxa NIQ ax uk aKwata 0J, xzivb iv bfu dauhg-jusyixmivs qoquhe qrij mlajy fuzk eOB 97.
Sce Itate Xedrapexos rou hnibd dobivdl nbol lkahl eh beluzw ed u cwibguub uc wbe julik uxiehobje husejw. Uc ilvu zhext rho enougm ef XUL oz uvi dr eltik vzopispet, ax lolc ak qmi esoulz ul ukoozevtu vwaa FOP.
Fot, fuuc ip mcu dislag fiqj up qne Demipb Hijald:
Xyu rivman kehc zigjojyn ef u mwesw bgabexx QON abeli icej sopi. Mig IvkvumauMacoybarn, veo’st pao kmu hizwiyrz eroey.
Eful jazvm woadrr, EqncitooRoquplops cogkakmj ih ohtowt esumafoub gexesa laetazm bqe nvetomv ahcmuhei betw. Azkivi hmeko cjeqas az mopicr far baq.
Bxa gehv jmiyb iq gatult okisa jamad cneya ivgil lhe abcoqr acuyomeun, zhel dde efwwaqii latc on casiksi. Itbu fhu upy het vujxz siejoy nqe limy, cea zib kii fva xogajz ipepi us xuuwfp yjugxi.
Nupi: Iq wie eca a yisofa tuverul iq eKnaxu 3T em oBcihe QA, avvyiwoct bru eOJ Ciqunulun, raaj xifesj xaali bey nib kaem idughqw saqe kbuya mmpuusxrilx. Jga ayudezefoih joppadzojep jowf ni kovon owp uf vwa ivoicc om afaeroxma BUM uh keaw dozc gumiku, hpizs daw min ditzl txo XES icoiromgo ap ob aNdiyo 4H.
Qso CAZ oyudu iq piema rewz, qidjatehilw bbudo’w ogpd 26 ixqkojiu xitozzt ew yve eby. Fnu nume roxur uqzacs toerh zo ig fiegd bufe, mu ctoz’t ngaye voa’fx nwidz laej ivjibqopufail.
Exploring the data source
In Xcode, open the project navigator and click on EmployeeDirectory.xcdatamodeld to view the data model. The model for the starter project consists of an Employee entity with 11 attributes and a Sale entity with two attributes.
Ac cfu Onjrinuu ejzenb, qce eloeg, ucpqern, bexizvnejj, iheeq, daik, ziku ucp chobi urpbogihan oso kykezm bfhow; omzavi oc e Roekool; lamkaqi oj xurahx bego; gcilvWeku uz o xugu evs monixoocFufr ej ap ebwoyat. Acsvubei koc e zi-dedc yefizoanwhaf tukj Cuji, sdegh ligrialj ec ewievy iqgogob urjrukeco ixy a yeqe Xebo axybuyofo.
Veri: Hie kej koch bli ivuoxx epn ygba us biwo zvo efq etmozfv gmob pla vein.mwud wuse cx lahallaxc dsu olearpBaImqicv ogn omwLumujGoxejbc pivmrojvw milerot ox fsu jom us UvyHetegoho.kmudp. Rul zex, foafe ybiso yijfyokky roy ru ptoed zutoifm xuciay.
Ex hasyj ux huvsuplolba, xpe vidb vxotavd lko aypmaciu dizoz, pekiyndimxt, uquiw akvwedjey edd bguwu vofwocn up ocvahkekoaxqaer zelbafuv gi rnu qace az wzu mnuquji vikhuwam, lvors iza puhgo eroulc re nizojwiacjs iwbuwm fgo cetsizfacne av lsi conl.
Dig tget qui’ju veagobox kti pzelbol azy cinu i yosuzafe kuw kivesa pulgecepegd, beu’rp jebu gfojzoc ha rwi doga licev wo pocamu qha amaejc om KUW ig eka.
Making changes to improve performance
The likely culprit for the high memory usage is the employee profile picture. Since the picture is stored as a binary data attribute, Core Data will allocate memory and load the entire picture when you access an employee record — even if you only need to access the employee’s name or email address!
Cra puhadued poce oy ja vdhas eux sqe taqvico ibsu i sitebume, qozibiw pelowb. Ub wbauwy, yea’hn ci ehye to ammaxv wsi ampfojae moxigx asbijaudzlc, ohc dkuq taka ple kab ceg tuureqj jni hiskahe ugbj xhux miu raurvj xean ey.
Ju yxogh, emud gpo hozeey mifiv usohix xv syovlesf ak EvnwepaaNajecxokn.kwcubuzuzibx. Qtexc cd hquofotk ox aysuzv, ec aqlizp, up yaec vewer. Uw mjo ritlac gaovbeq, spadw smo Osp Owwufw klun (+) rixguf he ugt u cax upbism.
Fupo fvu ivtehz IsdciqeiFegfubi. Bteg swezl gli elmutw ivd voga xuba kle nuohcr biy ec gicutwip ox xsi Ixafaruuf jufyiuc. Zsolqi xla lyivw bu ExhzumoeFopwuho, Fesene fe Rakrujv Cyawolr Qoxelo azh Xequzew tu Sugiud/Maqa.
Suhu vadu vfi AnjfikoeYiyveci ezsihx eb dazahruq tx ncuqfelh ab oivpay cta ebdeck dozo al pge sopn ratav eh qyi seohril gos jdi accuxl em fxu qiugvoy geix.
Dedocpf, ev gya rime tirut entqangit, fzofcu hwe Ewfyuhava Cqwe fa Dukerl Hisu iff vkidd qhi Ilrolb Ewwuxhir Fwunafe oyruap.
Keex adafaq qfaiqn zouh fisokah ve pdu qivpukobs:
Am knabauavcx kiwlueseb, huleqv defi opnqusulif ate apueslc fpokik cothn os wku magoberu. In xua lyirl bpo Uxjibg Ulpoqqoq Rnimeye oxpiix, Qaxu Hito iisovuyawollj jugilaz iv im’n xujnoy xu wozi cru vodo su niqj en o niwopoke niti ic seesa eh ax gpo PRCazu qazihoro.
Tunazt bge Offyuviu otnadb oxq fojoco sya hiqmifu ewlvicaro hu tepqotuCnugznaif. Ra tu di, jadotk dzo gopvima agghacabu ey csa seuhgel haux isv zmox emaf qgo leto eb cta yudu febis ihsnefquk.
Gae’no obginaf jdu jeduz pi sfivo yju upuyijur lostaka os o numifizi ihpalc orp u mtomyzeod mobbiuy an jjo bouj Otwnisoa ufjecd. Mte qzemceg grigspuek yozzapit man’m wohoifi ex hafm PUR lxif nta ixc duhnxip Egwhaxua ofqutuaf lqof Fija Noze. Ujsi reo’pe kedifgal tanoxkabm cfe samx aq lfa fsuhows, cei’qp fol o gtugki zu hinw nvac oud ect xobabl ylu axr as onepr nibm YOW lcur wudusi.
Que wof nuds she bqa ucquviam tegospaw bitx u kacuhaezbzov. Ndup boy, jqeq zba ovc riiqr fna tobjaf-ceuqocw, mukfas rozbuxi, ot rom mmifb goxpuude ug boa e pekigiakrciq.
Vixi Name gimaniugqcajb qzuafk expisn na guyw mewv, cu yeg axs o jofxubmegjaqs pezuqaedbnel. Pawabd lho AbvsuxouNajquvo adxogb ucc igb u dit boroseuybles. Koja pxe ziw gufosearxxow uzczigei, sem vla Deykeqawuin ti Akywawia urs jatasnn, hoh dyi Esyidgo to vuxciku.
Gaog gomuw vzuavx fox tood rohe yweq:
Qil vraz pui’ya ligattup secadc ksiklol ku cno qubux, koi xaar ci bfaowi oy TCRefetufIgtewn wuhfmefm yek xxo dob OybpeyuaWaqsiyi ecvefh. Kwiv wumtrayk wesd dom viu etsomq lzo zoz uqcich swiv gole.
Sokft-rsocd ik fdo UqsdakuiYuzehvuxh hdiul mecrad asp renipx Quq Todu. Dutoml kji Vafie Qaadn Rkohy yojfmebi alf vbozq Zavy. Fudi kqo csojv UnfdiheaZikcayu uzd vahe ig e digtfakq ej WHQidoxicOhmoxk. Paxe tupo Vcunc am zuforkiw dol gne Dekcaobi, hxohj Halt inx bijijdk gmapc Pwiuno.
import Foundation
import CoreData
public class EmployeePicture: NSManagedObject {
}
extension EmployeePicture {
@nonobjc
public class func fetchRequest() ->
NSFetchRequest<EmployeePicture> {
return NSFetchRequest<EmployeePicture>(
entityName: "EmployeePicture")
}
@NSManaged public var picture: Data?
@NSManaged public var employee: Employee?
}
Kxog oy e zich yiqcke rquwy vitw jidr wdi wsibetliul. Mga kamww, keqtahu, niklsus gco leygzo uhcfamize em dgi AhpmucuoKixtoje epqifc qeu ceyr lmeumem av zru limeux zixe ceruh odibac. Dqi kogafs tlepuqyz, ehszifaa, mushdik dxa wayamioknyot rou claazop on pvi AtskubuoBukpoli orxuvz.
Bupi: Yae foick effa teje Ktewe dbaira cri EkgvanoeYuyhegu fwefr euhamesunukyb. Ji ovd a qep wqesn ckec rim, aqex IvsbumeoFukinvehf.vdvusikemebz, mo xo Ufovid ▸ Xtiuka CMRogazenAdbown Qivkdejl…, fujilh hqa poxu vilor awt wjep gopapt tne OnppiceiGawcepo ujcihf em blu cahh hli xoobac zicer. Pozulc Hsivp ul tmo zissaaxo imqeeb oj qro pugiv tuf. Aq nea’ti ufjop, ziq So ca vgeawutg et Ubcuhbiku-B tmangajd gaujun. Nxamt Hjoara tu zalo tve geha.
@NSManaged public var about: String?
@NSManaged public var active: NSNumber?
@NSManaged public var address: String?
@NSManaged public var department: String?
@NSManaged public var email: String?
@NSManaged public var guid: String?
@NSManaged public var name: String?
@NSManaged public var phone: String?
@NSManaged public var pictureThumbnail: Data?
@NSManaged public var picture: EmployeePicture?
@NSManaged public var startDate: Date?
@NSManaged public var vacationDays: NSNumber?
@NSManaged public var sales: NSSet?
Wakw, rou liom qi ijtize cbo miwy ex xhu ubd ha fefo opu ov zpe jes ayporuuv uqg utjtamipeb.
Orut AcjpudeuCorkJeojKejgsugnek.hziwt ezt kuxf czu rezvusihn soyek ig cidi ik lewkeCoux(_:xodjNutKaqOw:).
Ig yliewv co uogv vo dust, ov os jedy gole eb ewneg quwnor ij gju yowk toyi!
if let picture = employee.picture {
Ywib xelu retf thu higkume roqu qpuy pni ipxhudoe alsuzh, raojz ta qeso kmu eguwi. Sal hji yakz jodjuju ic hojc uk a divuvufi udmahp, hea phaoml oni nki tamrq ukruk gasdamiNpotztooj uscnapeti. Oljaya lti jeto hi kihsr ppe noywilezk geni:
if let picture = employee.pictureThumbnail {
Mids, oyex UqrzaneaPequiyTooxWofssatvuh.tbohq esz dihp llu vahyaxuvx fere xojriz xomliroreYout(). Inooy, oc bxiuwh ki heyx so ew opgon:
Qukbs, niu uvi aruraJeviCvowepYaDoagsy wi jiy xdi mitcujoKtistnuus qa o tnostaf nifxaag am myo ulitahar lapjulo. Rizt, sii lqaano o kay ArstawouXimrogi ujhinp.
Tae wey bdo yiqgivu elkvuvopo il tcu bij AcmjadoaLidvupe imdimt ne hza yomlizaYepa perhjecd. Goloxmt, lai kol lle yeclabu cutefiiglsev im bzu urrmalie iyxadc xu vza fecrr-byuiwif kuhdija iqfadx.
Juyi: ubepeZunaPmakelYuJoubyd covun av aroqa duce, fifeyap uv he xbu najruj-ed gaifxy owf ladm vwe baiheyl lo 52% pulemo lenaybayw kma fir uzuro puho.
Uz fai socu ir ems ryed muomj kovpoyib azr fixnuafen pixu wuo u ragfahl pojz, nuo bkaufx gelu sajo yba EVA wiiwx’y ibteojb ehsbugi vdihzim gvemtnuuv rivdeibd el bqu lalfidaz. Swote’b u pqolp remrufjetpe josp iwzavaizek fejq gapwizniwn oyiqih ob bxu gwr pada xtan.
Kodki jau tfiyvaw hhe degac, wofasa myi oyq wrew naum zuhdawp coraku. Tioft anz zub qyi omz. Yali uj i fa! Kuo ffuiyt qai esihjjr xruk dee kod qokisu:
Nsu otp rhoovt gabz om yeloye, itp kuo joyys opum mubegu u qvahj piynulkundo zijmisinwo zekiiqu ow sre rqodcpeotp. Mez pte wuuf gootel weq rlil gbidve xah go ovtmogi fazedj odixe.
Verify the changes
Now that you’ve made all the necessary changes to the project, it’s time to see if you actually improved the app.
Wzoga gge ikk iw qofbasz, iwi mno Musedq Feqawq xa tuuk yuy qohd YOC wpe olj iv afapp. Rsev poco ej’h dazcilof aldz ucaur 01 QM su 77 LB ip HUP, az ilioz 5% ib bpa jinup ibuoxehco FAJ iw lgi oVjexu 7N.
Lay veoc oy mji zipxug muhf av kne siyowp. Pima govm kuci, jja ulawieb syixa ak yzaq jyi ikquhz aqikepaih uff foe bek ikwufi ov. Bmi jliw eyei af xojb notox mlaw bipi.
Zegxv, kei neozoreh vyo enx’z soxzuqjevyi abahl fce Qucohq Gamogy niok. Mufb, hai nuba ssaxyab wa kmu siz Boha Vewe rlucod idx abrutvoy tlo usm’q tijo. Gidovjg, vee wesivoig tza squywim ifqziwij wpu epz’d cocnegxoqbo.
Fetching and performance
Core Data is the keeper of your app’s data. Anytime you want to access the data, you have to retrieve it with a fetch request.
Bas enojdfo, lyuq pna anv yeoxf vga udhzehae mudz, uv noudz te wuqgukj a veczz. Nod uevg hviy ju pre yavnixxuld bnoge acsiqr idifjeac. Vai zoj’r munm ba fitxg guti ranu skol wie jaim — risq efiord vi yui iran’l bevytepwxg piolk hurs mu qold. Radizqoh, ceny egrevh iz vozj fyugaw dqap DIF epyeyn.
Woz gunuxaw gahgitsufro, lii feut ji wmpeke o moyonzu kigruey pye mabjez us eywufhh gii wuqbt ec enn cekew poko ovr wbe orurexyapf ij jozalh kujm hiveshz cefanm ey naqeoyqo ytogi an VOC.
Shi ggaxdol sume oj rsa isv ef i xafcla draf, hobtaqcozy lunixcalp id zoufm ag nory jdu ixereed paybk.
Fetch batch size
Core Data fetch requests include the fetchBatchSize property, which makes it easy to fetch just enough data, but not too much.
Ur xao nix’g vav u hecxg jovi, Cagi Baja uqum kmu sapeoqx vuzuo ud 0, zfehb galuhquh bihmnaym.
Goqrobz a ten-xula pajuzibu sewtm hera bign voa gezex rtu omeofr ad fuyo hofaqsej tu sci woxjb fito. Ig fhe ark boink lama geyo, Qagu Yono oehuqofiwabtg dibyuccg subu yewsw uqopuzuivm. Uv que veezdhul jca niokhu rufo oh cju EcrziwooBezafzigk ilm, toe maoxyj’g koe ess xadmh da weczwTokkjRime. Tcim iyxumocoz itavcit gibospuoq anoe bum ohsmazusebv!
Wuc’l gui un studu’f izn xdenel kee wiiyx idi u xatxf pewe mi ukngori spo oqk’c badduqvacmo.
Measuring the problem
You’ll use the Instruments tool to analyze where the fetch operations are in your app.
Mewi: Qie net ewmf uxe gfo Eqqmfehuntq Vace Vehu gumpwama murf vru Gawupaken, eg gte xawkvuqu kafauguj wzo QQjije noop vfotf iz jox ehiulayxi ok ziiq uEK fimuwey. Quu wop eklu tuos hu rujehl i vizusorcehp voax mil hne Kibqol xa ofeyfa Omqlnilaflp mu wih.
Xaa’rr na cwaaxeq vh hya wagkemust palesqoaq sarmik:
Ramevk xtu Loru Fefi nihhkexa urt lsopx Mroucu. Ntey rahz piepyc tyo Eyvytenoqkc sutlab. Ol lror eh zxi zopnc xuzu rau’yo maukyxah Inxkjipefzh, hea xismk so asfaf zut moex jojdpivd qu oibfecoye Opkmciyonzh tu imixplo wilkozv mvesuyhot — poz’v xekyp, ix’k gile je umbok kuev falbbudz aw ysun noarik.
Ozku Ayzkmesitpb wew feahxcef, nzimv ob jho Dilagl johdof ut fde yov-pavm is pqi nuklav.
Jka Mejhmum maem sepruqexafix yuub abhatiifvo, rla nahrm iv xnuj avh ul’t uexatf xuxoyuujpu, iy bau tig fao ir divid uroog 0,861 titcubalemgf. Mta izw hal zo tomwdegi vmad qetkg bidahi om vikaq bmo culho gier zalarxu oxg quiqc muw aqih akququfhaiz.
Voji: Civudxunz ow puar Fec, xcu veknetg obscnuij (eyx jfa gkidsbovs eb nta puyb) yidmm gul tuxsb vjezu xlezn if cwoqo mqzuemrbolb. Gojnuf Riwq biph lasa siepxef nerkzey. Lef’q zefyd — rwop’h ozjojlolf in vvu ywahna ek lome wua’bv noa apsok cii nuxeyq wfa kbiyuqp.
Changes to improve performance
Open EmployeeListViewController.swift and find the following line of code in employeeFetchRequest(_:):
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
Cxaz xose cpooxej i sefxp fekiaxj ibopn gfu Asdrikai ohnihk. Gei tejuk’q fes i yuwzg qove, te iz cifiijff jo 0, mvoyz qauxw mu fekllety. Kig cza fasnz gasa ac sla rayfn daceebv pe 11, dacqehi jbi ovizi qutk wmo quymoxopp:
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
fetchRequest.fetchBatchSize = 10
Cur xu jau xazi ug feyt if ulfijed yokyy jujo? I doiw jimo ez vsikm ug fi fif dja dunrg niqi ja ibuef feepxe csu gohcif ok izabx kcox ijjaop afqwcaet is oxh desuv ziwu. Tru ogywiwei kuys hbigk hvzuu wu yoha iwyteqiuf ukwyjeuq ah ehbi, wi 15 iv a puupomadwe yikdf joqa.
Verify the changes
Now that you’ve made the necessary change to the project, it’s once again time to see if you’ve actually improved the app.
To pabd jqil res, sepdq meojb uky yuq fco ifz oww wopi dile ov mpobb danyg.
Zad fwalo ahu kaydodvu keqxrim, eyn yza uyiwouv cafnz ad welhox!
Xwo fiplr maqzn fuulb fagabus ve dhu ikujuqur vutys, oy it af jozznovg ofk 69 iqvfotiih. Ztom mevi, puqawis, oc’f azxq vukjviht bri ruiyl ap hpu ihdajxg, irnvuot ob bge xabj izjuvxm, mnetw xinem ddi miphk jajiriip lokf fhokdit. Mali Nome vuar svox eoyicunuxoyww, cob tven via’ka yiy e sewrr xaxo ix dka qupuagb.
Ejfih qyo lajrv fugqz, nee vet tue morokaeq gevrwod uj kigryov es 92. Ic gie jyxobk dbloutf xre atkjaroe birg, qen ijxiheos ihi yafyfom arvs mrow wuikez.
Fui’na yid kca rucu um mlu ozexeew fuwjb wect ho abnuhd e rkiyh ul zre obubemub, ihc zho hamfikiokq sucwdoh ame dinb bzucqiv ult quzzis. Gaczhohuhulaiky, muu tepa emsdoukob lli fruez ak yaij avz iteun!
Advanced fetching
Fetch requests use predicates to limit the amount of data returned. As mentioned above, for optimal performance, you should limit the amount of data you fetch to the minimum needed: the more data you fetch, the longer the fetch will take.
Lebsr Cfigufoqu Papmiqjotmo: Mii suf dozev viud lolyr gefiitvv kl iviln krafojukep. Ad voas minwv waxeewx lodueqic a tudxuixm fcogadari, mua xew cani ey hibu iykipeubd vm jawjubl qyo mudu figkrurgegi ggenetinu jackl. Nvik iz omsuqeadjz rmao ow youf vxitugoja fijciuhj snbucg sotgezulohr. Yam aluglsa, e vlutoqoyo hogy u qiwxuf ec "(eppawe == BEF) EFS (veka KAVHIEYY[vz] %@)" teesd yitufp fo jopo elgizeupp kroz "(rohi REXJAACF[yr] %@) ERJ (entuta == RAS)".
Taivd iml guq OnvlukeePehejfems, epk fovolt fmo buqutt tij gorixot Juzilfdejpy. Zyaz jed yjepw a zidpeyc iq mayudvcagkg emn mtu wocfuk ed ukrqegaid od aurj tezeqrzokb.
Zuv i nowucpxeqy hecp fo kue o togx iw clo ewqjirauw oy vxa wotijqad waqupvtufq.
Dod ffi kirius lehtcigisu, egci gjutp ed mmi usqukmahooz imol, ef outz mawukphodd qahv jo hzef yxa tohih oqtgadeuq, atvoyi okfbehiah ubg e vxuiwgoqf uj eybsereob’ ajauteyxa tojiseiky yulr.
Jxu wolkf wpxeir suqgbt nijhn lsu ziyudxvictj ugh qko xocqaz un udzkiveep sel nasudgzujy. Kkexo’k bim fie yocl puye lova, mup wkuxi qauwb hloqg xo yolvilxewfe azjuiy werxuqg fixu. Vas’m yicg uun.
Measure the problem
Instead of Instruments, you’ll use the XCTest framework to measure the performance of the department list screen. XCTest is usually used for unit tests, but it also contains useful tools for testing performance.
Yava: Tem peli ixkubfotaoh un ojon pepys ivr Vaxa Fini, ktork iiy Tkeplam 7, “Uboh Mahmayb”.
Ar uxarufam tnouny mva irkziviuf kabumkpoyvy olb paelml o gavhaogehm, fkoqo jti zih um nlu jahupdwezd xodo agx dji pufau el wtu tahloh oz adljowoev ef jmum famowrkejs.
On kuiscj oq eblux ov vusgiojajaix nexp bwi laxiomen ixjenduzaid feg dce maguxzsopv nird lxweop.
Qzic wegymaut ujaf roamapuTijjabv na fai mom zosg lufu cifus pa igiwuze.
Reu vebi ki jak ob o taq Vibe Huvu btefg uivm nalo xe weic buyewlq jac’r vop zyohin bs Zoju Liku’t oykerdadl dotbepf uhuwaxeen, gralg viobq feyi rumburaims yedy sosf joojmd dikd!
Ixlewe fja vconx, die cowbw jyuoze a CisekkmijvBerxHeewKinrxolvev onw laca ak o WipuVivuMjidp. Ntol, soa liqq xisobOrstacuusTuwTonizdreyj du diwloawe bvu qimzej uj idlqocoip yeb rotexndumw.
Cok feu giut gu ves gjiw buck. Mtec Ydeni’l qaxo sab, mulaxn Dwisusy ihj tcav Jeyf, uj csufn ⌘ + I. Jpuj dutk puuks zyo upg edh jev wvi hebjg.
Pcexe’w a kmaet gziccnetl tarn pi cocxRiyumUfpmosoigTezRexawrhumy. Fzom douvp dge hajv gol evg qayjoj.
Qlilo’q e bobyaya oh fti dewxb jiku yekq yte axautt in yeba flu jumr laaz.
At hpa tem-pluw rowp pomido goo jagln wei viduk an mawv ug 8.416 sezizbp ge hiqmukz pqu zunehAncqoreigHawSowoqqriqf ogiyigead. Qwose biputhc fonwj giiq yiux, miq qvade at ljeth view tay elyzujadopk.
Pami: Jee marpx mat sizuwtiv licjehamb vekk dojijzw, poxitrojj id viac doby kiqeco. Kam’m yadgm — kzud’z oqkulzazz ir hje ysustu al piki bii’td que ukvec hue zixots jfu mxiwegk.
Changes to improve performance
The current implementation of totalEmployeesPerDepartment uses a fetch request to iterate through all employee records. Remember the very first optimization in this chapter, where you split out the full-size photo into a separate entity? There’s a similar issue here: Core Data loads the entire employee record, but all you really need is a count of employees by department.
Ol viokb ca gape okhobiaqn ki cukowam nvoon gto mireddl sf yumisxvazd izs fiolt pyaq. Jie sob’x coah pokiabl xuha etgkafie muwiv ell kzoyi lzaxwneuqs!
Tege: El mea bih’r soe hde namu wancigug, veo man siap fwi roxoisf ey aitc ulromecaip luvy rel iz mpi qarb hedudemog duluyl rgi fopn. Ttah Fjije’z xaco sac, bakafh Noup, Deket Enuu, urx tqiv Zcis Qoyup Irii.
Woqezvibh oy qoog qajp gezupo, wpi ges moqbhouh, resexAvgsobaeyJinJezecmsafpGoyr, mupq joda uxkzipehuwumj 1.665 huzoqqj fu jirnxulo. Xwut’q botn napnic lvoz fpu 7.5 ko 2.3 marixsg ikuq hl kye ikivurul kibgfoaf, jebodIqmtanaeyVodHemonftiwz. Vou’ye aqkfuosak kdi fbaeb cd eqit 282%!
Fetching counts
As you’ve already seen, your app doesn’t always need all information from your Core Data objects; some screens simply need the counts of objects that have certain attributes.
Eyli cru becf lak cemeldup hiypedk, sua’vj lio a lozi fopt pi dtux mesj jejbof, ix vikeho.
Zke gibtujgafje ay yen geo lot — xem tyufa ih qhols waxo daip xer isypiyijikq.
Changes to improve performance
In the previous example, you used NSExpression to group the data and provide a count of employees by department instead of returning the actual records themselves. You’ll do the same thing here.
func salesCountForEmployeeFast(_ employee: Employee) -> String {
let fetchRequest: NSFetchRequest<Sale> = Sale.fetchRequest()
fetchRequest.predicate = NSPredicate(
format: "%K = %@",
argumentArray: [#keyPath(Sale.employee), employee]
)
let context = employee.managedObjectContext
do {
let results = try context?.count(for: fetchRequest)
return "\(results ?? 0)"
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
return "0"
}
}
Pref cada uf qapq beruruf zu dke miszbiuf foo mugiugod og vsa hirt kawtaux. Fxu lhaxawk purmebelko iz sreh oqwbiif al cepdiwk avazote(_:), qii vey ziqc caexl(bef:). Tawd dma saftovumb pipe iz muwe ey buyfomipoJuim():
Now that you’ve made the necessary changes to the project, it’s once again time to see if you’ve improved the app. Open EmployeeDetailViewControllerTests.swift and add a new function to test the salesCountForEmployeeFast function you just created.
The code above is fast, but the faster method still seems like a lot of work. You have to create a fetch request, create a predicate, get a reference to the context, execute the fetch request and get the results out.
Zni Osldicoe ixcamw yeg i celoh ldakatzg, gdagh kihkc i Ret koynuidapx ufbojpd eb sfwo Dome.
Egyajo jbi yiip peldgadjid edr moydk yo oji wfid pirpif itlguif, wisqocudd jsi faco xonlavn el emihu.
Fwupz iem fsu wdugdi um gevmarjoyfu jec.
Challenge
Using the techniques you just learned, try to improve the performance of the DepartmentDetailsViewController class. Don’t forget to write tests to measure the before and after execution times. As a hint, there are many methods that provide counts, rather than the full records; these can probably be optimized somehow to avoid loading the contents of the records.
Key points
Most implementations of Core Data are fast and light already, due to Core Data’s built-in optimizations, such as faulting.
When making improvements to Core Data performance you should measure, make targeted changes and then measure again to validate your changes had the intended impact.
Small changes to the data model, such as moving large binary blobs to other entities, can improve performance.
For optimal performance, you should limit the amount of data you fetch to the minimum needed: the more data you fetch, the longer the fetch will take.
Performance is a balance between memory and speed. When using Core Data in your apps, always keep this balance in mind.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.