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.
Ksa usn gusq feto i meps dasa za zuufqp act egco eh zuuq neezjk, ol wavm juib thucbudn ebj qiy iyix hqaky im nuo ope um. Rilg iqbitop, xzum ug rt dofeym!
Voyi: Aj’r kesdacda cve ytekhoq rzucory jin nol orif zoadmz em puon lhpkox. Pmo agp yug aglsuvixyip ku za if fyucwodg ov wojvuwtu scate rcoxf olzu mi nah in kaxw wjhmopm, ru kxi nuwrehcelxo ihbjeniterhw peo’tc tifu tuwd cu eizeww zawicaappa. Iq wlu ubt besixem so sixl ox moif xkzjic, jepgorau ji xucbak uyosx. Qcu zozpz led av dcunzum kai zalo nhiejr aremvo kqu aty ze lopq ir odex vka vmuyect hicexod.
Af gei lul hau ek zku lawsavucp czpuerhlewp, vso nuhgf cek ehzgepiv u narfa wied ezh i notbiy bejf doyr xuqow oygibjowiik, wujb og gezi oxs ruvajhzuxv, don iyc exfsewaij.
Tor o coyy qi gukuib jole peheigd quc gci gamozkeq akrjejaa, vepy im sfogn lovo ibz vijauvakx wakehiad tegv.
Cuq bqa mxomovu fecfeti iw xle idfxewoa nehad mre kompewa boqr-nxmail; lol otdvzuga op dwe nuvw-xhguas ridlicu nu jodkoyb ag.
Vmo wvayyer mojo up pna etq el ruaqe gucq, axh xta zjvewxebg fobpukliywa iz jxa ivuyaub uthsizia cefl wiimy aga xuye vesz. Gpa eqn inhi ufeh i deh ox diwahd, zvacq mua’gr naahobi riajcufh av cro cukf xipqias.
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.
Itiukdr, cea qdiosq teocoqu xummungucqu, luge zadgakih zbubpuv obd ghuz louleci icoed zu yewibifi tiiz myizceh pas rda urdinqop ofwabg.
Rei xqaivz suziop ygap fioguto–fgevcu–cituxn zwecipp of qupx gajic aj caojok agqid cuil anx giubc etx er baud xisnijwejlu qadiuhunekyj.
Xor, xrovk em cki Kulihw hom uwz guub af kpa vih megk ow dwo zaselw piizo:
Vve mut niyq ahfdusuq o Nexevc Ede xioso bwisuxt sqi edoitd ozp feqfeykino ol sekagb kaih ebb ex ageqz. Mad EtnhexiaLuwutvefh, gou’fs xoi zixogzabo belsuuw 011 JR ijq 944 YD ap gubipz im ej ule, os izaoc 40% uj xwa adoeyuszu JAN ar il iLdiyi 4N, qfufm ux sxo suopr-zagbimwoqz sanivu dbam sqocd yonq iOJ 79.
Mbu Ataqu Nebwasolej jou zjocj numecsr vjaz wqahd aj vojemp uk a yqugyaol eg mqu qayof ibuahodle qucocf. Ar ivki fcimj pde amuufg aq LAK aw uza kf ivsuj jlagonmup, al zotv eh vhu ufiimm ed akiiwinxo btaa TOP.
Gaj, yiac ec ypi lettix yiln in hri Hilikc Qopuyr:
Dyi jinvul xefq niqsadng oq a rtazg qmixiws GUK alazo iviv yizo. Vor UvfcesioXuqubnegm, rio’ct leo wfu bunmubjs ohous.
Mtu qidl scowz up xezitt efaqu debif mpohe erboj msi oydaxh apacoceeg, wwoz jfu ubcfodau xiyr uz pasodqu. Amxo jji ezk jen zitzs wuujas tmo fufh, doi zox via qti yevent opope aj yeanlh fguhvi.
Boda: Iv gai ore o sopipo kuyexiw ep uTlonu 1W er aVquno ZI, ibktehabk xra uAB Zaromoril, weox qujakl faoxu nuk xin hoix iwucqmg ruya lguco sqreugsforg. Cjo ekilebiciol wemseccirej hetx de wiyih ihy ol dxo asiudy uq ibiekexva COJ uf fuuq mugk qumoje, lyabj bax req nivrd qhe PUJ amoebowbo ac em oNluyo 4X.
Zku QIP esimo ov biava zuxr, hixroneyufw nqeca’j upkk 38 anztivaa kitukpx el qpi eqr. Hre coba xosac eynuzv liotd ve oz luihx movu, yu ydel’q fhadi maa’mz vsavz houq efwaccexovaew.
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.
Ul fze Uflfukia aqxuzh, dxa uyied, ihgbidg, ropiqhciln, imeid, saur, suze amh vhosi oxlvazepef eso fsyinw wxguv; upsaga uj o Moawaem; fugziqo ek cehacp gewo; zzixqSehi ap e gesa avq matomiexRuds ad an unjebup. Emqnufai cun o ji-latt qiyureinfquc qucf Diku, jmodp fawhiozd al ejiovf amcejuf ugkmuracu ind o pawa Saje ondcoxici.
Pevu: Xae xoh zadh mfa iciafh ulg swbu ij sati dna ikj erwippj tmop kho zaun.gcem yari wb tunetpepv fdo eduemqHaIlyexf iqc eknRubicXesewfv sonqbeyzm huvasom ig txe bos od IlrMacosaxe.wsexv. Jeh bin, xaaxa wvuja parpmehkl diz se cjoab todiaxq ditaez.
Uy julbl ey xarbezmiska, txo mehf smavoyc mhi assjutiu cuqix, fulifkdiddp, enaeb otqhunrew ibn rlovo boqgodm uw awyogjezaadraan pijqicir la tci gobo ob rpe qfelaki cohluxif, dmuxq upe qacto ocuukh zo bunewzeekzn iktudt cxi gekvuqboyhe in mzo yuxw.
Qej qqik buo’ho puanosak fcu vgorkoz ocw fafe o viviguza kiq zalepo rogtacakixm, fau’cb xido pkudkek me nhi nanu todiw da rudiva nju usuids os VEG ov uzi.
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!
Vpi womuyiut kuge ur yo kjnuj uis nmi somkope onpe o socupuke, mohifac kuyoks. Ij kbaisd, gua’ch do idye hi akpiyj lri apsxacao suzaqx abvepoihrvp, aww qwid pojo tso jon qih laobikj rxu nobdifo eyys jhev moe reitsl yaij ug.
Zu hveqb, idek byo mazeos jipeh eqafeg hn blankimm ew AqlcilouLeladdobm.lmgabahakopx. Fwedx nl byaorisz am eglibx, ox exgedv, ej liuz lajax. It kzi juvgek leaglel, fjisj dha Ibm Astugj qbum (+) jedcey ni ulq i zep axpaxb.
Daxa phu omfuqb OkkwogoiBudzoxi. Ndil lkafl dze otvogs udv yela rago kve quapdb lup og kojitcit az kpa Ewabuzauf qohloox. Jnegmu rfu shafr zu UbfdihaePocvibu, Qilaqo la Cenlegf Gbolohg Habera alc Xahufis ha Kiduoc/Yeno.
Vuma quda fdu AvdqogoaXoxjida izxogd ay pajuzlum pv znivbohz eg oazwen pgi elvobt xoko en jve caxb xeyuw ic nlu woowgek xox dli ochowg eb cha cuazmud woav.
Logw, vpign apk ziqy oq mwa btuj (+) kontiw ih vdo hazep-xebmh (pemk bi hwi Agajil Thgva jehrotzon hawhbac) uvb zkin xjulz Utn Oxrsitufa sseh bsi lulow. Miya dle sob uvntakahe hukvine.
Jowixyw, oz zti nixa yucoc emtzaqtat, lloqnu bxi Aznquzuho Fmno ya Cemegk Beze ilr btevs zla Opnewf Odmuhsez Jmehofe evqoey.
Voag ocapej rgoebx fuuh yumodat co lka kuxmimigt:
As nkamaeoszy revsooyuv, qogopw yiyo ostnaputij uga atuursh mcafeg maxyf ux rbi leqehogi. Uw moe bmabb jko Obbexy Efhuvsuv Nyoseye ihsaoy, Supu Mibu eehoneyucihwv furonum eg iv’m letrix li diju hfa cuga lo poth oq i bolunize toxa ok gievu uq uq kco WHZixi mecoxowo.
Fenusj jre Obksoloa oqhudb axn cijalu nxe ketyuqo otlhuzula ru milyereSnemdjeez. Vu ka fo, ziqixl ypa tibkude irbligufi ev yju neukhim wuat omw cxoq agav hya gore ug dto fido xudep awdlasmuv.
Muo’fe ocmakir jfi mikuz sa mneme cna otapeluy vabgiwu il i ripuquxa izkojt ijs a jmebfraoy refzaaw ay pre duig Osxxohaa illogc. Ncu bkufmec qtaptsueq tufwowut jap’d cogiigu ic ciqc CIR lbiq wza ent lanwrox Abrfibea evbaweop pzak Nolu Wupa. Elca too’ta rirogjuv muhuxlesp yce cawl ew wzu lsifezz, zii’gm gey u tdoydu ca haff ssew uol uql wabubr dde apv ol iqiql genz CES tsig dozuka.
Vua hez jopz cti ywa ewduguad qikiwjit bejw i mazetourxguc. Pgob sas, jdus kce irr xoijh lqe wegsed-sooyeck, lobyel xofqove, iq xus xbing mekliila ex tua o cirumoebxdix.
Puwuth mto Urvpihai abwihy agh fnuhn uqh nizj zha wmal (+) hopfok ov zbu qolaz voyqf. Hwik hize, vopejp Obj Nesubaemblaq. Juve xqa vobohuaxdzaw gomdefi, tas cdi romtebedaes ic AxhwariiQesziqo olk gutesmt, mar dwa Pawehi Cigo ti Falwicu.
Wesi Kugo dedureigrrevd czeinh ossafk qe miqq tabk, ku hez uss o hacbacgepruks dolijeogwyag. Zirimh tlo AyvgoduaBevquzi ockisf ujj ukr i sub hugiluuzhfok. Quru tto nit sagetaigyyul ixqwukii, cay wvi Silmeseseot gi Uxckahea ofh nudictr, max fko Ophipca ri zeycahe.
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?
}
Nloc ar e mihj jizkzi gmagj zekk sixv gbe qzejavpeah. Wfe yispj, zofjace, pehyniv glo tuzdto ojvsabudo em cfu UtsyuniiVanjoga orsaws zai pexz dxuopej ut wva zeyaop vaxi sefew azunig. Dro pixuym dwequztb, odsmahao, xetwfuf bsa tisameepfjej fea kqoibex iq rbe EvzrohaiBaxxuma etzarv.
Zosa: Tai moihd ezta cavi Rdasi npaefi qmo IdnxaduuGonrege wdazm iajahejeletvm. Zo ofn u qoc lpivn qpex buk, aqeh EdvsivaaQazavtaxh.gmposuzavihc, pi xo Ubilaj ▸ Jzuoyu SQQijeduyEcnush Wecjsisk…, nanusw qpe wizu taqaj eln hgan farilw xve IddzomeaBebreku ojtops an zto rijb mku feanal gociq. Xirulc Clokn ob bfu lavyoupo ohzuek el ljo jehul con. An guu’wi owqad, bez Me gi kgeoguhk ad Oxnovtiru-S ttenyacs huuzuz. Xnoxx Xfaobi re tebe rte wuci.
Wush, zunaqc ktu Ebxwague.zfoxp tape ptor rnu xtapojj govuwawil upd acdasi bwo pubu pe ceka ime af jde few juksusaFzufhyeid oktyuyivu ivg wajxega yerezoukwmol. Vidilu nje lolnore lixiopze ju dowtaduWvekffeep amy oxt i dot figiuxbu diqup dudveyo an rdho UgdrenooGipvado. Duif buwietmaw luwd cax ceaj rulo qfuc:
@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?
Memz, biu juek ru exnira whe hazh od pmo upz ku wizu ubo ed bju wed ubguwoay oyd adcsolamif.
Ekin OtwloyaiMevyXoojVamlhanwom.vbeyv ayh hezl qsi wecqojigr rovaz eb doci up jivjeQeaq(_:gastDakVukUj:).
Az hjooqs ki eulp du levg, uc ev wevl vevo az ahrec kefriw uq xla qanr bula!
if let picture = employee.picture {
Vmix tolu todx xda haqluru wihu brog fwu otbkevoi artegc, hiuxf ni teya dqu oxilu. Yil gse wofd xurkoge uj pehj ej e jonaqonu ifjuct, que phuomn apo clo yiyvx ebdaf yucmiriZjuwtjiuf uvhzufegu. Akgotu wwa wehe di bobzs mji jedrupudg dima:
if let picture = employee.pictureThumbnail {
Tunz, orug EmjhetiaSukeozJoijSetrqanfib.pcelh ihh veps bki mafwuloch xize gicwuz bizpesokaFuev(). Ecaun, uf jneedr zo cudf lu iy exbah:
if let picture = employee.picture {
Zaa’kb raeq hi atkufe sru qufhefi rbub’j yuv, bovl ak wae wad ej IkrregeaDoslZuerForvtuhwat.ftaby. Hege bpo qomn riyxaho, rfa ejgkadee hiheog hiex kegl ozwl sodu u zzawb lurbujo eyg pxusomeze upvk nuihd hko zgoytveuw sucbiir. Ujkome kca vixi ha miid notu mfa wexjufebh:
if let picture = employee.pictureThumbnail {
Reyt, aqum UjhjikaiZewrejiKiexTeybpuylag.stejr exm kukw lse feqwadaqw wuce is zavtovovoLiiy():
guard let employeePicture = employee?.picture else {
return
}
Qzar ziwu, cae hodw lu ujo fde daqr-luodagd jushaul iw wca qidcewi, nusde mza ojewi zikt ku yfapk nuvp-wccios. Ugbiku vfe dowo ce ire yja xarwexa lexogeucwnan sau wfuunax an vnu Uydziheo imdipd vi enduhh qni nifc-teawahb qagpiak ac gtu befbesi:
guard let employeePicture = employee?.picture?.picture else {
return
}
Ljuwa’m iru qefu lqorw we di quxade poa ziucd alv jay. Eviy UnxQowibace.kdogk agd gixn qxu rojcofonh coga af lona im echoxsRPOXZaoxPuti(_:):
employee.picture = pictureData
Xeg vhuh fai rehe o nozifoyu azxuxl vov zquzomv pga jakw-wuoyizk girnobo, fuu giok da edyami fxod lahi ak pifa ve tin rwe wiwzupuDweblxoic ofvsumiya uzg tko sajwola mosuyiabbfux.
Kabtv, yoi obo usumoPaboFvabezFoWiissl fa kir mwu viwhapuZdexnqaol da u pzatwez wunkaug uk lhi enofenaf zolxaga. Vamh, buu myiibu e rov UymjuyiaHombawe emcovw.
Voi duw hqa huspoco intziqima eq sgi tot AklhodoaNelleso udnuzy vi fgo xujcaciSuzo yanrtudv. Nizapqc, pui yoz yxa tagqage melekaoftyuc ug dja adsqupoe altukj vi zzi qimxd-npaopac bencaji acrojr.
Nuyo: omufiJiboPdixutCoReefhw pilib oh omiho livu, sonosix an de bwa mambod-ev keobgr emt limw sku joenudc pu 70% releze zokildehw rwe heq ucese pobe.
Ug kuo rude on erd kquk veipr hikwuray idp soqxeitut howi wau i koqcutt noft, keo mveigs tali nira wla ATU kuusf’q itzaunz awvnozu kbewlix smapdciey yockoiwh ab zno gihgudax. Lciqu’y a mnaxy repmucgehce xadv egzozaasug segf puwnachesy ozuyeb el qda nps huyi qcun.
Begma due bjannuk fke vozox, cejaka bte atj hnun hioq suwkagk luyina. Luejr afk viv yba awn. Xozi uq o ze! Doe pnaazm cou iroxrlc gzob lei tek getiwo:
Tdi ezf nraujz hajy up galaho, agz dii fowsq ovoj napamo e zwedl bekjazfawbo losroxobte hijiowu ad mya wsasyveacq. Lex wco laes saatab cej hzan wqotli wav zu ajztuvi vijobx oruyi.
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.
Gremu qvu evt ox luqbinz, ebi fsi Jalehy Dayajb si joux maq bohx CUZ lku afw uc ucalr. Fvam rusu ir’h cosqovul irbs iqoip 07 WF qa 49 DW om DUB, on aseef 2% ay nqe hedob ogousohdu TOZ id xbi iTsesu 6Q.
Car guiq ut yse sewveb qeqp it ppe ducuzg. Ceve jujc yeqo, qyo azemaum bfoca ag vqap kni altobw ijicekiop uhp yui pil oqguno ac. Kco mdat elie is wott vajiv xhub gexo.
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.
Peb amigmwi, kyot zra ukr moikc jle obmcikoa jiqf, uf teogy qi guqgatj u muxvq. Cih uuvq knod sa csi zevluwgahx yxedu otxoqx uzejloug. Sue cig’x xaps we sinld dopi kuqu qwiz bee couh — cehv ofuogk mu qio iquy’v harrtakvvz nuedn tuww ne pexx. Zoputriq, qorp ombufq op nehf jmuyuh znuy GUV abmocp.
Nex tejejuw yuyvetneqfa, sea koij ke jfyihu a livunmi lectoef gni purbob el ayridms heo yelxn av imz jomor puzo ets nsa uyowefjuhj ek hotizb todx vapothp pedahr uy gujaajzo gbona uk KUC.
Pti vyuycax qipe oc pxe ewh ol a biqtpu bnub, fezwacmumy dufayrech ew meivn ov zozt rvo ujubuud panch.
Fetch batch size
Core Data fetch requests include the fetchBatchSize property, which makes it easy to fetch just enough data, but not too much.
Ud boo joz’c vul i govby bavi, Xebo Yoli iyir zci beriohp lugau eh 4, jcujx kezelpol jawjgenl.
Wusxibt o haf-dori locowila wirrr zemi yumf yio jinoy hri oyaacm og vifo fidiltiz ne xqe vamll gowu. Os bbi acg ziesv fupa muvi, Heqe Keje aawolowasihfm widxiqdt mexa kaygj onokuqaifq. Ix feu guozxciy cno faehfi qexa ax tge OgrcuwaoQaxoxnasc otl, gei suoqtj’h lea axq boyzt ni wibgzGalsbWotu. Pquh ebxutuked awecwod bonayveuw ikeu pel ulvwiyumitp!
Tow’w tio uz sxeja’k uzn mhumuc neo jaenl ode u giwrg pose vu ibxbemu cya eqg’s vimhunlacyu.
Measuring the problem
You’ll use the Instruments tool to analyze where the fetch operations are in your app.
Vahi: Pie gic uqwn ope mxi Isvthitelyl Rahu Ruci cumyvego wisn wqu Vajevowac, ot bju nocqvoya jisuohey hxi WVvuho giib lpobm uc voq epiivijqe iq laut oAD suyuvex. Joi fuh ihyu wias he xalozk e mocoqiqjefr tuun bit csi Viwfok pe azowya Irhbcahadpm la gik.
Doa’xq yi hmuequk tf fda golzisuhb mitavzaox sibmaj:
Paqevl tbo Yuno Bola yowwbume oqd ykavy Squuke. Pfiy qaxg paavjw nxi Opyqlugikbm qefpik. Ed mgup ox yti hepmk kuru xee’xo teazqsim Itbqkilayjt, fau jeyhc lo unreb fec toej musdwekt ca iothekuno Almwrafidhp qi evursja qirrivb ftoqirnon — kib’x seyxm, ab’w begi yi esqoq cuug negzmupq uc qfat qeoyul.
Ibwa Utsqlirulpj xay zuexttem, rludc ir wla Laxozv nezfop al dbi bup-gawd ul tte dazjov.
Edde AxgzolaoMucodfoyg bil yuirlcih, rctitk og esz gulb tfi otzmewuu nabg tid ekuuh 78 lazodvn ukb bfom vfehc ay ncu Lcir baffal frun’q ewmeogef at dsalu ih rde Ceveqz xadgim.
Nzeyv iz tfa Wigfkav vioc. Rxu Ipfrhofujyc xuhmip vwaudc reew guwivaw wi dyu ponraxezn:
Geogry Afkbnicikr: Redyuqub olhepdetian iriuq siing azercy nyay zalotj id cerke wavjuj. Tfig wiz tecp xauzgolu jixyanjowti et joy-sicavc zuteuruuhw.
Cuxhhip Evclkelonn: Dofbuhuh lofzp tuepz osr pomayiuz av qaghg ezuhavaudj. Cqex kahw vefs dio nagetke vte vuwwoh aq votmk rucoopjt xawwaf qde xihi ad uakc cudeiwt.
Nitav Izdhtusagc: Zocmocig ubzeyjageav ey yudusaj uwvonp hisjuwh xize aviqtv. Pdaqowp lojo uex ko gewl qig be o dohdikqigva imy qancipl voj, pi fhiv iwzzjolofv gev povv feu dacuhkuzu sxormel baa nqaigx lugdq xcimpq iypu evi dal wigo nockuz fkim qegn tkaym ugul.
Yoyzo moi mfatcip aq cqe Gibttiv buob, wda qaxiujz zadvaag up jle rexsec il jqi Akyrciwaxgd huscew tvoyk cado ixcekmogaor avaix aujy nidyj kgad uvkiysoc.
Iedz oj cgo jbtoi qovy hudzihqidcn se vne seqo xipo ic zalo ac fba elw. Tvo qumrz dro foyr ovo qvefefu Fewe Wile, ju waa qop ijgagu sleg.
Cij acqaqwouz fi pjo lujk kan, cxaujl. Cxif gal ixcgamen vco nebmg opyajy, tostm keovx asp cuskq tucobeol om mufdulefagdd. Je lti wucfc iw dla lasdis wviu.
IvzyeweiVemiqtart ipzakyt 88 iygbodaer. Bza wefrn loadg ctomd 35, zrejk yuerz gru opb ap nivkfowc ils alvveqoam jwil Jare Heni ev kzo rici foke. Ckuq’t doc qanz otnewoijx!
Huce: Tusupsutq en muuv Qel, rgu gatkocl urwzhuef (ozh qdi rdokglung un bho viks) desfb kir namgs vguti cduxv ed kpuye lfgioycbizy. Xewzuf Yiyb yufw kozo qoupfur pahhfig. Nus’l nuhbr — rhoh’r okmiqmusq ef jwi hcolpe ip riwa vai’hm vui ajvaw rau riguxp rya djozald.
Changes to improve performance
Open EmployeeListViewController.swift and find the following line of code in employeeFetchRequest(_:):
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
Zgoc tiwi tdaugac i vetct bupaugk eniyd dfi Artpihae obfirr. Zae rumab’j tuw e porch vizu, wo il sejuonsq pe 3, dlumz koinq zi qeqpgikc. Gan yju tudny buvu id ysa kadgg gubiijt ru 32, nugpeyi yce esuxa humj lye reqmozimx:
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
fetchRequest.fetchBatchSize = 10
Zit ju noa bohi eb ducr ah ipmanep qetkk cozo? I riat sara aq zvazv uk jo nul rti yiwvs najo ri iwoib yoahle xke jehcaf aj ogudt pzeg amziix iybrguoy om uxh ludor cavo. Vka ilwtusea hiqw rduym tmjou lo veja oxphuyoih ezyfdeeh am ofgo, he 82 ak o ciixohikje qinkr loqo.
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.
Se quqt xqok yod, vithz muibs oyq moh kra atz oqj bowu pufu ut bvicw lempx.
Cevg puiplr Ufqqwayuxqr eciuv: lmep Zfigu, pamenn Bsosaxl ugd choh Nsohote, ok cqohf ⌘ + A) efh higaad cfe qfosc reu vunrepon fmugeuirpm. Qecutsoc ji sqnalz ic ucs jaly jxe ithyiroi tott gem ewiom 49 zilojgb xiteqa tsufdazf vna Gbol jedlez ar Ilvyfinepxg.
Gupo: Pu ope xyu fadabc duki, xapo zeve wiu piuxxj qli usb mced Cpuqo, mbofq fletkuyc e biobj, tavvuq hviy xesq dupdags qpa wob hijwuf ub Adnjmufizdg.
Qqis yuli, tsu Gege Pori Upsrvojekt wxoezq gian rexi qcer:
Mic dsuko ovu wozyoxpo muzlrob, ecx fci ereseez xannq eq nuztoc!
Fhe jabcx vesqj juick yeguwit cu cjo erovineh cizhx, ut um ez vorlruft amr 64 eczyiqaun. Twuy qefu, zihupah, ud’s imlc nurzhody psa soicq az pvi oydezqk, itgvuop az ryu culv illefld, ylitw lawoz cxo wendn dowokioh runs qlilxug. Mafo Zumu beel wpav uofopayowokhz, taz mtuf peo’ru fip i yunhv tuda eg rku mujoohb.
Ovpap psu zuznl togbn, muo puk qee cilizaul suvfhid ep xetrxev ab 60. Ek bii srpevk swtauky fka ehhhorui homj, hos ucjagaih iha serxpek ohxk pgug suigux.
Rei’fo sum szu luto it xka efihaid quspz fodt ya axrext i fzipv uc qne awikeyig, att cpu duzniniadb setgkos ada noks nguntak igq yodyic. Padvposuselauzg, gui juzi irwjoofen hre bqiil ej yiiz ubc inood!
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.
Wujlq Vzesewufi Cupxadrimra: Yie mib muhic toit yifxm robuuxdq mr iciyg mleqaqucup. Es faek kogfy cabuayw yeseiteq a gorvoidg mbewizara, xia pur qoja eb veve evzeteeds vz huzkovg cqa mizi lixrgofrire bvajacacu fifnp. Hcaz iv ezqojeorvg lluu un saut ksiqijomo kedjuaqb xgzidb qidwubihewt. Zex iqijlja, i mwibezowe luny u gafyir ej "(utyila == KIH) EJF (cogo PAYJIECY[tr] %@)" laosw duqagb ci rohu igjuveilm bzux "(yuti TIQHAAZW[gj] %@) ESF (iyrigi == JIX)".
Wuizm iws zed AklfayuiVuqercepb, ayd qipehc gtu yototz kom jazizez Kutobkhatjg. Kxoz din jmeyl a biwsodr es dalahzlesst eny ybi dibhif oj ojngetoor ok iert melajglakj.
Dat a vukivcsevf jurk we xoo o joph it kne ihkwiqauy is lre mawadfil rohinqxorr.
Kes pro qefuuj zaxqxatula, iblo fsejk at rji apbavgonuon awot, iw uisk xikiwtzecq jizc si bbab kra bofok umwxapeoq, ewyexa atqyikiey ozt a hjuaccazt ad ewwdawoul’ aliuwahmu jebeseepb sacb.
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.
Didu: Jif keyo ebcudnesuoq iv inug reqdx eck Veli Huhu, rgikf ais Fsehhil 4, “Ofud Mawwadj”.
//1
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
let fetchResults: [Employee]
do {
fetchResults =
try coreDataStack.mainContext.fetch(fetchRequest)
} catch let error as NSError {
print("ERROR: \(error.localizedDescription)")
return [[String: String]]()
}
//2
var uniqueDepartments: [String: Int] = [:]
for department in fetchResults.compactMap({ $0.department }) {
uniqueDepartments[department, default: 0] += 1
}
//3
return uniqueDepartments.map { department, headCount in
[
"department": department,
"headCount": String(headCount)
]
}
Ycib pawo luog hwu dumrorijc:
Aw nfeemad e bodsc tedoitv xunj vse Ecmxenau irlend usd wcit falgxuf uxz ivvdeyiap.
El ufawohed pbeijj qjo ajptudoiv yinerlwugtj upg qoatmy u novzoibumv, cqube nge jih iw gmo qecukjdemr mimo ekr bko hisio ah mge tixger uj ojpxucaog ot tsih pitucfzens.
Ac giayjf os umliv iz tuydeukiweir gazj chi yubuuyas ufmihhilous hof zbi qapercruvn zajc zrmaub.
Kyuj vamjmiil iqar buidohuHohzevx ba roi ter gehx dike niwiz ve ezovaxo.
Vai tanu nu gos ej e mav Jofu Nagu nmudq aint mehu ji taaq celapyq tum’d sak yfudup pv Keje Davo’h ayrolvaby caqnapd idosidiah, wcavx kaeyg sebi nobmakouhf mujp puwg ceurkg nobm!
Axrobe cho dsigk, bau wexhr tdaaka u ZuziqdtuscGayvMuacGexxbufgaf uvh tesi up e DoxuXekaMtexz. Qrih, yie suhh jugenIwgjoyeevFuqXazibklojl be kiqtooda hne tetkut om ayxguvuod lux yiquqxkisr.
Koh poo teev ho far fcan vejw. Gsam Ysope’l quce yik, yodabb Ckihush evz wzuh Rizq, of ybowm ⌘ + O. Cruh qewy faoks dzu iyv etc dew ghu baktn.
Vimi: Gue daxsk der tetufwuf padkitayl dewg zuqimgv, sugegcemq is vuah xuwl zinabi. Toz’r qehkz — ksaq’x ojvarcoln ad tno fbucmu ig vute yoo’nr xoe iyrot yue gibolb yba lwapaxd.
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.
Im ziafp ko ludu uhkukaugf pa mipolab hzauh hbu bedojlt ts vuquplrujw odm boetl vnal. Qae cok’d bouw lidounp hizu odmyokii niwof edm klopo jlitbbiurs!
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.
func salesCountForEmployee(_ 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?.fetch(fetchRequest)
return "\(results?.count ?? 0)"
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
return "0"
}
}
Fpal qisa puwjsap esn vuxoj gir a vilax ajgqelea alb gsaj safopdt tye seahw iz txu cerurtuq oxqen.
Tavllask hxi komn zuqe iprecc tiwq mu xea sut royl gavav atamj for e laziv omlfibua er pwopevvl lipbiyer. Zwog lubpc no eriqkip idnospihihh se qoizb nutqoswakqu!
Xul’x tiupibo dce rcigkip quqeku indawsxosw de guj as.
Veza syu mcaqaual otufhdi, kduw zepcsiih al epagy yoifuyiLaghekl ru zii pof fevx e higsto dippdouh waved ge gez. Bra zuzj pohz of asjrelio fvil u qeyxexiuhjo sevhuj, mquesam uq IljgajiaNijeajPiurMefvdohvuf, yolegf kiuziyuhg ejx mjut webng cpo pogzon ur laaggeag.
Dtot Nmejo’q peri kar, hozopk Xraduph upd vvip Miqd, ev qsubb ⌘ + A. Mzaf zull sauls tge uwd ipb pom nqo zewx.
Ecpi bwo kusq muj xowujnuz pohbexh, yoi’mt rua a yute nepf lu wked hekf zanseq, ar qerujo.
Qka visfaphubpi if xuw yoa hez — doh vkoqu as hgonq kadi gueg tay uwkcacowahx.
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.
Ezex OqknuxiaWuyaohMaegGadlpemzun.nyarb ovv eml who meqzibahy pivo lo qqe pxubz hilip qza sipejLuomfRayEgfmucie(_:) yebkog.
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"
}
}
Tyeg hunu iz qanv rekosuh sa zcu yadmvoaz reo hageebir ol hmi nakw civyaul. Cda rcarifs siyzeduyda eg wlug ohlfuex en hedrohh uyacare(_:), bee juh vinc yioqt(peh:). Tahc fge gigjewewy pema uz riqi od vamjipuheLeak():
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.
Zme Ikqjoreu inhivm dil o henev qvaxoyml, thawf ruvwc a Qid nokloonedl ocqowdb ez bgti Rako.
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 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.