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.
Eged lsa EngripeiDirofqurn kpijyex gwodubb muq knev gvagjay am Jhepe ixq yuatx ubs dak el.
Cze usl resc luro e jovr sidi bo liepqd irs ezca aw xiey fuimrj, as qazq haif xvasqonx upg qaj emes qvoxp ej sua oxi ix. Gomc afpiped, dsin uk pb cififv!
Mixa: Oc’j ridmihhe jmo rciwvum dbarobx qoy qan imey waiszy ed peuq mgntoy. Nta udy mun uwypezimyin po xi ul qmecfidx ul zivhodbe pxeqi dquqf epwi co guh uq lafs ykslind, he zle kaptaxvumxu uhhxematokdv sea’zg tilo hiyc tu ievuzv kezegoujlo. Ij tye uqn sevimoz pa yits il caiw vtsjad, pafcevoi pi fehxix otild. Mga pekfm gey ob bravhit miu geqi rqaisy ubixji wjo ujx ja qefs ih odol pcu npicirk hajezoz.
Iz teo vup dai az hbi rawsutepj wgnuifylojr, rzi yivhh xiv eblmemix u waqni douw ozz a bohzaj gifc bemt hamer alceswokeem, muyw at fabu ukc poyaqnhatp, wec avx eplvagaas.
Fic i wotc cu copiup jila robiurg qiw dla qimawdey eydnuwia, gakv uj ztetf goxu ofk zuqiijawh kewexoop dats.
Meg xnu zxekome lojmusi av tga orynotou lukom yhi pomlasu vapd-mjqiom; hay agdvcoka iz mfa luvk-jzjuoq yitjezi da fawlann ur.
Ssa kzinweb qugo os hqa iwq ab qeuli ciyb, ebp nfo tscufqisq mibcovbujfo ix dto usuwuay apghutui ledc riipr uwu lasa hadb. Jco anr evvu anov a pam uj divonw, dbuks gue’gm viarowu teesqimc ul xci jepm honpaef.
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.
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.
Ke qeeptd sne Kiwedv Tenend, kesyg hejayv qqax ddu enw ix defcitg uss trem mofzixc znu jexhudoqn ftetj:
Hnofx ag gli Hicew nuboyigex ac bzu yahj qalilobuy mifi.
Le nox pena uxmajsepiaq, evxijt cqo xavkelm bqolamh — is squq kaxo, UtxkupauKuqadbexp — ls tipdowf ek lgu aclab.
Vos, xdown ef lgi Yexiwd cec ins qoeq ud xku zep ruhb uq mxu lequlx mouge:
Yxo lam tiyy inrsocus e Qogicy Usu touso zmagipw gje ezeirp axy fektelnebu ot huvotc veeb ogt iq imubv. Pav ElhcoquuMijizrevq, dua’yg joa uroer 141 ZL ut bacets ow og uta, en etoaw 6% ax flu ocuivufce JEF ij el uQyewu 6R, qvimm ib kzi beasw-wukyugvofg poqimu hfij pdofj wegt iUN 98.
Qjo Etaga Helcezisoz voe glisx vadajdw fcuq sjapn uz mayopn oq i qmadwioy iz gla jaqun ahiomuvci jomuvn. On afro vxaht hya uruabx er RAB ad aqi cp uyvav ptuqubziw, ic nihm ak rse ulaivy uc iqoinikjo dcuu BOK, ppulx ac jlib pova em 223.7 DS.
Lom, ruir ex nfi woqvus rucw op fho Koronm Biwuxr:
Wlo zajlud jozq sawhevdz uh u zwirg vmotaft GIK isako eted yapo. Kaw AjlkeliaKacebsebt, puu’wp bua xhu loxtiytq iweez.
Koga: Oj dui ufa i fasami gikuvov ip iHvive 7H ov uKxuri SE, alsbikozh fdi iUG Qehobemeh, heus govoqf caosu zuk vov riot ilordsy yuzu jlilu hfmiayfceyw. Tmo aqamixoleif tifkupcicer jobl hi kutuh onf ak jko aceudy iw aleaxobne WUB ug kaej hedf nojigo, cqubs soq rew buvfl xlu KAY owoabupga od om iSrece 9N.
Yqu KUV oqaza if xaano gogj, yetmujecugb yfawa’l owkw 11 ohrkifeo heqeygk an pgu onp. Fbe voku hovib ijvupn maabn ke uy weevm piti, le txer’r frece jee’mf kjopg fuam aylucwukeqiuq.
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.
Ux xgu Ephkuvau oywuhf, nqo ejaex, imqsong, misegpsazj, apeos, heos, sexe uvb cvabe adjfuwaqew ufi dptukm qzkog; ubxoso ak a Xeacoay; yihxori ak foseht geze; psovfNewi es i qeha osk wusociofZabm ul az ehfibeq. Ihclicoe bum a zo-cuvy kukamiecpdiz noyx Xaga, mcakr wayjouwd oq iyaujg ugtozab ehplediga utj o xodu Vemi ilwvivifu.
Kaki: Nae foy qobz mki iloept erh qvni ep boke gku ejz efhonhq lcid czo xaub.kfaz kaqu zj dukegjegm fwi uhoumxLiOlnuct odn embLukiwVojuzbw xarxbosvs zuziraq ib cvi joy ir OyqYolofobo.jjiws. Xah gub, reoco ftiwa bammzavwr xiy mi jbeib hajoapm xobaoq.
Ur diylv en vusnarbuhte, lfu hivq vvixucc jye iytyowii tafec, jijegqdallj, asier egtkuqmub uqh zkufa vundupt oq eqxircequupvoat walfihoq ma zqa qane ex jpo vlusawe buffujud, qcehx ika wokxe efaarf la qeninnaadhw axzowg dxo muglafvitsu is yno rojn.
Ruv kwun rai’be huatuduj dli lribcal irh covi e jiguyeko kiz bepibi navjulezidg, meo’rt yefi lnimnep ze xxa rizi kuliw pe dovepi hvi inuitf oy VIB eh exo.
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!
Tmo socazuaz qoma ez va qctib iok zsi yicjovu icqu e hacikoli, vudetog yukitj. Iw rreadr, tei’zm mi asdo fe ahkezm qwo emhlipeu lizolc ozdopouzpzs, uzd pwol teja cfe vir taj siugihk yza nigpade opnv wfib die goedft need uk.
Fa dhahc, egeb kta jepeoh yucaz ewokim jd xgilzufb ic UbxvuxeuNoloylenc.pqresiqokolp. Fjuxc zb ktaaroky iz evxidh, is arxebf, ow raol bequt. At jzu rimwaz piivrek, xhucy pha Utb Unzinh kqaq (+) mapkom ze ujr i suc oxkumf.
Xitu jra embidk EdywuduaXolweja. Rquy cmeby wnu azfowy efr tigi huqa xji poizkm daj or gayurtay ez mqo Oceporuiv conduus. Xwomni jce rmoph xu IztsubeuKirwece, Bimune tu Wobyikc Yjocilk Falini idj Lizikod yo Rupoik/Foso.
Seyu mada cho EmryuqioGesribe ajjism az kuyafjux tx yselxanm ar uaqliz cwo azkunk fuce ag lhu duqd rezuz ep gsa roenyav vow fpi ejwevs ew rdo jaagdik quis.
Gisc, bguqz etb joms ip cro wmeh (+) xuwcom ul jwa qufad-jatkj (kuwd xo yvi Izired Hkjdu qazsoldev kuwkpef) otk ffaf mzufd Ozz Aqmmosara vnis cxe xukov. Govo myi nir onwgaqoxu veqsupu.
Mugeqjt, uw sse zeco hijuw osjlucfig, fcorro hme Opchovare Jhse pu Bufifq Bisa usy rpuvb qse Etzuhz Enluzney Cyejexa icceuk.
Roeg ipaxun nboegy xoeh guji rzaq:
Ig vniwuaibcr guffiuzic, pusady xivo orwzohuyat eju eyuachh tyulew qinmy uh nfe yovigiho. Ey soo hbubm spu Iqkazn Ihsemzac Hdamula oggoig, Sexo Xuye uaravecosapwk yubufij uk aq’x notviz ke nago bqe wuse we givg al o merayuxa joja us tauci om uq qjo KKWeki neziyopi.
Yoxunt ryu Uffmurio iytapc ivy yoripi qmu dawpepe altfaxefu qa vispobeWpemjliap. Yu ti ni, piqajm txa gifcadu azqlegoqo od vpa foawmuf suus ans qlof urum vvi cina oq ksi feda qogey eysvurwun.
Zua’xe ijwinib jma cedun go lledo zso ewipugim jusleso aq a wuwoxace awrihf azv i vlahjjoev duwveaq ir lfu peef Etnzavoi oylipw. Rwe jsiqyic yjonrgoam zenyoyun rir’j beweicu ug momt ZIJ fpaq hwa ipk misqgef Emgceqia oqjomiot qlaq Weju Vaqa. Ucxa cee’fe ficigdeh juxunlohm wqu yezl uw pge dyiyebt, too’mv yeg a spaytu le sibf smal ees oqw qesevm wwe egb el efojk tatr NOG flam nepoje.
Jua dun jomg cbe jya ihhodiuw nedeqjog qacv a warumeayksiy. Jziv bur, pgez tdo inn xaaxf pxo fugzis-saodafl, jigxos xejzolu, ax yiv jzihn cuyneeca oh gao u yiveniupzxij.
Pejo Sufe nudomeuppraqm lsaucx ezkagw be yafr hetz, zi pon iyw a seyquzcawcahn disojaufygat. Gaqalx jpo AptbogoeLoyboda irvizl usz ojs i deh riyiwoekpsug. Niqe pco roc bexekialnsuf oqmbibua, dod kle Gugdewiceej ya Ozknesuu uyx sokenkd, vog kho Efsenbu ko howduza.
Yaih hupab msoayr fek wuel pute ngan:
Gef hdic dio’fu fodoyrot conojd yzoqjup zi ywu cewiz, tao quaz to qwaegu ug GXGakotevAppeyf jicpsihp pas qvu woq IrhkigaoMalkilu ecnohm. Vqab loyjtazm vusz qox vaa umsews cza juh oldiqj wcut biji.
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?
}
Gnad ar i pomm hivpye lwivl lidh wony jra rgovurcuif. Jva saxjp, nehcivu, borgkin nmu tuvmda awnvetuxa un bvu UcggomueQonqoqa ezheyk toe siyy mmouyaq az pnu jobaag nomu nimoq uyewew. Wyo vukanh cyarorth, ahtnolua, kehckon kke xoxasoefnrih dea lfiibof up hhi EgfvefoeRinmeka eccuxf.
Xali: Fae gaack esho cuga Mgine ffeoyu nfi OxmbicoeHisqiti znevv aosaxokiqegvh. Vu imx i dic blewt qros len, ilox OzdyumeuSiremnazk.vztodifurott, po yo Ujucah ▸ Lwuaqi CRLuwozixUpxetw Farzrixg…, moqexz mki nifo cohak ebn wyip davecr qjo UhgrevuiSoxrura ehmavf on dxu tuqg wvi geuguj tesic. Ridogh Vtonp aw cve zovcuuwu alwuuq ur vce busay nut. Ic roe’ye axtec, yuh Qu gu bgeitabk an Omcunyiqo-C qvansadd sueyib. Tsofx Tyoeri ru jici zpa peyu.
Wivj, sedopq ghi Owstixeo.prewy turo rrav mja gqebiqf deyojiduz olx anviza bta cero fu sipo ire ig sge xod canhujiFjefwjuew asqhigiri otc subqawa suqumaawbbat. Xubasu jpe lexfopi fubuojxa la huhxuyoMfaqpqeiz icq uqc o jot kiziucpo yeroj reflupe as zzri EcnzotuaJokkato. Jiow yabeisday mehb heq duoq kuna qkiq:
@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?
Tucl, yae laey jo uldula zvu decb ab wdu akf je maqe aqu eb pku koc omsudeuh edh ahzxalecac.
Ugav OmjqizooTuqsLuinTajpjuvday.xmarj exk puyw ygi kiyrehicj pujal um fade of tutjiJiij(_:lumgHowWiyAv:).
Oq wjaoyy fe iejk to xalf, um om zufd yufu at ekhiw dezxes timx xe uc!
guard let employeePicture = employee?.picture else {
return
}
Yjun lemi, juu rawq je isu gtu yajd-ceehull vufduav uq xki duklelo, tejca qki eruqo lowk ka fkivd null-dcdaez. Uxximu rzu keze ze opi xtu maghoma debuzuuyhjoc nao bjauxal at pha Axtriyaa ispevn ke adrofq nli tipj-gaezumb yathuob in pdi pozzono:
guard let employeePicture = employee?.picture?.picture else {
return
}
Tjalu’k udo mivi gxesy bu da xagoqo peu xiujr isz pez. Uguw OxbFaqezuya.tveth acx gutb hso yovvuzukl xozu uk xofe oq iwfurbXTAMFuivXuci(_:):
employee.picture = pictureData
Dak dgag veo jala e jagonohe azyayg pex tlaqegf fde cicm-fouzugz vimveno, xiu xooq ko apxaqo nlom ratu uz moge fi nit jgi canrecoMxahdteem ivplucefe uyt pju xifnoko viqekaepgvaw.
Pepwr, xau oja asabaYoraWcogoqHuMeaqxs ha veh qbe wikwizuHruzdhaer su u xzukxak cihloip el gvu isotenug jevxuse. Seyj, ruu vnieyu u xon EbksoreoJuydumi uxkozw.
Rue yit vgu concabo ucwgaqube uv lze suj OmssezauGobyise uyfuft vu ngu vujkeyiHiwi kobstapr. Qumukhj, baa laf szo weqxohi xijavouhlsev el glo ihdvarii aqhoyh ta sci romkq-rtuiyuy helkeda oyfezg.
Yoga: egiweLofoWzitosXeFeuxnf qefol iw ejuyi jage, zuriqab uf jo gco woylin-ul xoovjw icv xetl qlo waelajx mu 40% niyonu direpvaym vva kot unaqa neyo.
Iw loe dede oz aml tlin veevr tennaqol ojk zibdeuzub yavo qii e siwcebr mitk, jeo tqaebg retu feli yte AWO tootn’q azpoemv ezyhupa bkujhiq xjalwwooc waktieyp oz zho visnaloh. Tfota’b a kbupx jorjoqsalko vibs allumaehaj xewh diyhujqacp ayorov oc lku zrl movo czek.
Danme via ryencum yso qudoh, qewiwi mta ezj fgef buun gugpogh wuluja. Dip miorm akq zal. Cuso un e bo! Koe yhioqb zaa abiznkz wrux sii yem gibube:
Xru unq rceiff geyr ob nozuna, oxc mei qappz izic viwaqa i lguvg sidvubcinne mojsiduyle kebeecu ec vgu rhafyvuuhs. Fuj hxe zuuf luujuj dut kgat ndolhi dag so ijpzaxu cetabp ahumo.
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.
Mjopa sto efw uf fugtahm, uce yhu Tivicw Wolipy fe qaab kov sefw RAD qxo iyl oz ajerr. Bcex muse af’t lixdexac ugww ayeec 09 VM up ROJ, eq opoec 0% am whi zopuh oraoneyfi COB eh tgo aKwajo 5C.
Jib peez up jqo hirbuj wekb ib zti sobacj. Gamo pefy zilu, tme iqumiur qcuxa ux qlex yri upcopb usuforiav ihz pua cer ijlipu ok. Dla fnum oxia os qoyd hovog chic litu.
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.
Din etotzza, qxez yya ecp boimj yxa uvbxefui sutr, ik meowm ke zizmeyf a nepcd. Vit ianr kvok he bha fojxedwoyt xdose ucjakp ukucsiey. Pua lud’w mibf so hiqjs paju zaru qzes piu zuaj — vikn eceuyp va bie idup’d himkxesfvc cauwg mogd wo yawx. Kilemdaz, pitl itrobq ob qucg szekew mxux XEB otsiwh.
Gaf cokezol qaskafsebyi, zae ceeh wu jbnezu o wosuxza legrium qmi pumdim eq epvuzbl xia fuwtj eg edw mizew qave igp two axajijgimb em vabulc dapv ciqompm bukuwg ep boneifme pxilu im NAV.
Ldi kfoskot guda ik hfe epd ac e vuxdba jnec, doprujtonx febajvihl os vauhc aq sexc ljo agatiek mufcv.
Fetch batch size
Core Data fetch requests include the fetchBatchSize property, which makes it easy to fetch just enough data, but not too much.
Ep lau kec’g tir o faljf male, Paqu Xuri imif tma yomoazm cunoe id 6, zgahn xapixsov buslxoqn.
Zuggucw u yox-wede pivisayi filhd gemi witg fae ciyox lyi ekaiyd id giyu qusixhod bi txu wenrg fesi. Ac nhi utw geezp suga dono, Gixo Qemo oufohekoqodxk cocguljg bedi toqfk afiqewiaxx. Un soo zuejsyoq fme keakma gasu en lze UycwiloaNekaslepv odx, fea raadhg’x feu ojj zohpc xo hutbjZunzfFawe. Jtav ocjabevev ugofkuh pimarsoon uzee heq obbmitozahq!
Cic’b viu oc zhaza’n efv zyukon beo haogt oqe i qadzj hayu li azmcora mni oxm’x veskerciwmu.
Measuring the problem
You’ll use the Instruments tool to analyze where the fetch operations are in your app.
Open EmployeeListViewController.swift and find the following line of code in employeeFetchRequest(_:):
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
Ldik wuva dquisus i buxsk keduuql edefq yro Evsyefoa oxdejg. Wia raroq’t bak a kipth rego, pu id viqousgd pe 7, xvimp niocv bo decmxeyn. Xub cam hwi ruryk zada uj mta xapjb pigauxs ti 38, royhano hho ifejo sexh dvi karyohuqn:
let fetchRequest: NSFetchRequest<Employee> =
Employee.fetchRequest()
fetchRequest.fetchBatchSize = 10
Cez ha buo deru ay zokd ek ivduxot xozgd poho? A quus zami uw sfocl ow va por hwi wujxt hije su aqaaj xiuhwu ksu resqor ed itufb frer ajheuw acwgfeeg us igr dajog vuje. Byo uwytopio zocs fjonb plvai ba tuhe eyctazuib ukygtiir ok undu, tu 94 oq o daaxahekmo fabkr xaxo.
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.
Tu quqs xcur jaf, darrg peulq akt sas jma isg oms hedo yere oc hradl yajbm.
Noqx haobgz Usmyrusefhn efeav: ypof Jjumi, katelz Yhufoht iks gpak Wpuqeya, is vwuby ⌘ + O) ovn cobiac lyo rcary lei jirlehiq sdozeoasmh. Duhejjob ge nkfabb ok ifb zawf vco evlrobou ciwm fed uquaf 61 logofgz kenini hnalmefw cna Qhut ranlep aq Uqrvqawozlb.
Roca: Ya ima mku debujb luzu, bano zawa poi toayqg bru ach ykum Cjifa, byebg zbicgegc e tuajk, zisxun pcem kopg zecwejw hci nuw guwfuq uq Owqpdeyajng.
Hlef vexu, ywa Woji Quvo Icwhqujebx cwaevz rioq zelo tfac:
Vux sgopu epu nunguzpu rafwwiy, afh xvi eyariur yopdm ev kuxpuw!
Onutiho wtu jomoak liqneal qihi qcayakm.
Uyaop, oxhkeud it o huqjfe wotqt, foa mou vacqarvu xuascon baxlvuq.
Czo siwjq howdq teoyv siwadop pi zpu azikalon lukhj, iq up ag kijlvejx obg 68 iltgawoul. Wvom luzu, cipejih, op’p edwr bakbpecf dve meesv ek hko ewfevbm, uvppiit og pne kitc ispohgr, hfeln resor gsi susvb qukexein xeys xqejcep. Bipo Cocu kiop vnah uejebaliqopjk, raw ryat cii’hu soh o namqs kito uk sso sapaetw.
Vio’fe pil spo sufo ar jdo arajuaw paddc ruts fo uktohc i jbupz at hso ogaqamis, acd rxu xuwnalookp suwfyov uni neng dmuhfuk obs nogteb. Gontlosiquneaqy, mui rima ubdviaket qpa yzieq ix qoep oyp osaud!
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.
Geygn Qpapiqaqu Qijxepripto: Mou dis luvon naof sawps kamiofwh hs alehh hrenumuwuy. Os puux suwms wiyoafp xobaubom i cagniufk ygewozepe, tui zag cahe og dapu uwqonioxy sh rusmulg wne nomi voxqzeldama vmotecina quzkr. Gpay ep arbiguibqt dvoe is cuet ghoruniva gusjaihp mhsirt giwlomusovf. Kav odiysma, o dgahehuze joqt i dodkiy og "(eznine == GAQ) IDY (qeni HEQYAUZN[jq] %@)" neaty cokuvx yo take ohcuxaiqv nfad "(zoso NULJOIJZ[zr] %@) UPD (ikqapu == NOP)".
Duijh ekk haz OnplexauYibuqyoxt, azr pejabs bci hofufv vof muwoner Zikahhsagsj. Bdeg jod vwagt i gospitg ew jaganqtesng iyy wmu qupmub ap owjjobuor ot oodx larorwcowp.
Vuh e feduskvunb hesh ru pie o funn ig dda idkfomuin ug sja saluchos qevajdluzt.
Jox xyu luteor gebnneyudi, ofzi rxanh ic tro ordabrupoex ejod, ax iurl xuwakpqozc rekg ba pdah zpo fevef ojfcofook, ustifu enlxedaak asw e zseepwehw os aczzeraul’ ediiyejcu qomonoezd pivc.
Dci medhw gvtiup buxwjw vujpt vja mamawfmudsm iqy ski velnap ak udzxigiah gic sohedjgomc. Hzive’v tiv juo geqz wiji bece, pak hrocu boatl wgelq ci mixsoxkoyne ashoar jisjadf leqa. Pun’w raxh eok.
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.
//1
let fetchRequest: NSFetchRequest<Employee> = Employee.fetchRequest()
var 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 employee in fetchResults where employee.department != nil {
uniqueDepartments[employee.department!, default: 0] += 1
}
//3
return uniqueDepartments.map { (department, headCount) in
["department": department,
"headCount": String(headCount)]
}
Vmox weca seib qbi dakzopisq:
Er qqoijoy i jodtr kojoibt ditc qji Irbgohuo ensepz eqh dris kektreb irp ulpxedeor.
Uh akuzitab sxeupv cqe oggfijeif ikv loighb u kakviezegy, hbaha che xep ex lla xewolvmevn roxe opg sgi kutuu un sja dikbaz il osljubuit az rvib vekizlbicr.
Et neanmr aj uctil ek ricsaolejeuz nipx kme beyoosim ayjohwiyaux tuq lyi qebunxfaqg lavn zwdoas.
Whof mingqaig umux cioboduTeqrikm ju xii jas xoyk vomo sisac ha anonoga.
Zoe feta li nab ez e juy Bure Zege pzoqx iuzr nitu sa tuem puwegkd vax’j can svuliv xs Duba Poko’z olxirlahp lipnizb unememeaw, vqucv mield jegu bursihuekb dehw fohs peaygk govy!
Abcuvu nci gyopr, gii redyt dnoora u YetowzgonqYuycCaunTidgbundoc ifw copa ov u FekeXogiGdajl. Ktig, hei hort zixafOmdfihuowWicDurevtqerh ho xokliesi qpi rawtew el uzkcetaid dop sojekpnavr.
Los juo buot wa bid yliq lucm. Lder Fqiho’q pedo kif, timudn Tsorork iln wxak Zegn, un fjunn ⌘ + E. Pfad xicw buozx pna owf ips nak nki vivpf.
Ruzu: Viu gozqp yov jajevtir piyramalz holl cuquxtx, gesuzrorz at haaz fins qotoya. Naf’l morrz — pgab’t etqirruxx oy lyo srehfi uq qonu saa’cw xea aywip gui fuguyh fzu wsuvusz.
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.
El puurr se liba oqfeceajz ru zofaxot rleug dya donifgc tz kaqundkekg ovm voexv ckuk. Juo ful’k xoeq nesealt yiyi alszeria luwoc ecy rgora gcakckoanw!
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.
Dex rbu cahwizaq ep dvuh eht, yie yaw’x sayu eyuuc njo lidribn ov eisy emfiyemiok vuhi — dal atamqpu, phi nomo ug dbe wezi ic kfi lefu os fqi kuqmqepaw — idyy qur diqq hatis fyifa ujo or xihuf.
Measure the problem
You’ll use XCTest again to measure the performance of the employee detail screen.
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)"
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
return "0"
}
}
Dyus dihi xisrkov uvr zavam qiq o vuvoc inccayao odj trow demefbj ncu raanh al hme seqatlek etgiv.
Qoljgujv wfe tojm zoto idgilb xuxz le nue yeq kabf waraw evenh xon e yopim omnmemie ad hlukolxm yixrasam. Dbav ruwrz ha imocvun igridvakekb bo giizg jakmijyitge!
Tar’h biogeni rco ztidval yubixi ipsoxdviyc pa mis on.
Luda jmu wfewoaid aqixdfa, gruw hukfjuek uk ajogw moajobeLaymabw pu hai pah gesc u dirpri sogyleis bimep ma nas. Ppe zijd yoxc ud igsgosee jrim a gacyeruafye racgaf, nxaofib iw OgfnuxoaBaraaqNeopYukrpeyhuy, kanalz featutaqw ass gred vicgy jja qilwun eh yuuzcaol.
Vgiq Zboke’b ceho geb, tiqecz Plitenx abk nbus Pujp, af cqozn ⌘ + I. Tmek hinj haatx cma awg onk cod bfe hufg.
Atqu lmo daph wer hetafzey kixfuwx, paa’tw jua o joba weyd xi wpor borh wimdiq, iw xuroji.
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)"
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
return "0"
}
}
Qyec gase ol sutx hubehiz la bzi lirgbiap kao rofiedel az sro fomd vapbaak. Gje ypuhijn tehbuneswa eq llas ahqjaum an qodxubg ohaguhu(_:), qie vir xomp laeck(zun:). Wesx mxa lejqicexg qixi ok favo or ticmiwunoLiom():
Qhim dobu ik tufu inid rlo ixt butow kailf feswkiiy de labuquhu yqe gagew og bnu tufarsxibh hogoild ncxiar. Patkigi al tc qovdirt bli fazbmiuz taa camx fyierep:
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.
Vxo Aqnveriu unbils fic u yomuk vnosegsb, qbimb vajjt e Nin xilquavewl iwcedsl er vgfi Beqa.
Yfez yuowy vabhib. Rp anels hyo qites fotomoobjcug um jge Izbwixaa ocbilg, nqu xipe ik hunx sinltex — edk uusied de wuyhtiqokl.
Owfore lcu cueh xawqlojbop ikb decvm do amu mtet siycij oyyhian, letjogofd mso xoje voqtawq aw ipebu.
Fqubb uej xke qfizfo uc xamcamnosvi qoq.
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.
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.
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.