Being a great iOS software engineer isn’t only about being a grandmaster of the Swift language. It’s also about knowing which tools the platform puts at your disposal, how to use them to sharpen your skills and how to identify areas of improvement in your code.
This chapter focuses on using the Instruments app that accompanies Xcode. You probably already know ways to use it, but the chapter sheds light on some not-so-obvious ways to improve your code.
As you read along, you’ll cover some interesting topics:
Common memory issues and how to resolve them.
How to measure performance and identify bottlenecks in your code.
How to measure and improve the performance of CoreData.
How to identify lines in your code that take too much time to build.
An interesting instrument called Timelane, which you can install as a plugin to Instruments.
How you can use os_signpost to send your information on Instruments.
Getting started
In the starter folder, you’ll find multiple projects. You’ll use them all throughout this chapter. To begin, open the project “TheExhibition”. Each exhibit in this group will show you a different problem that you might encounter in your projects.
Improving how you use your device resources is key to building high-performance apps. For the first section, you’ll cover memory.
Memory optimization
The first exhibit, A-1: Optimization, is a gallery of wonderful images from NASA.
Wlaqu ija rukz-daazadg jqanew. Ava it dmov zut a biyagijoav nuyhaj nzav 1,814×0,410 gamaqz!
Nhad uhxazer cav oy oqfovj el npa unt’n faxabw. Cii’qk usa Ujtsnidedyz si ozoybofq yyeq’x cuugolg pxih zulewr gnanjev.
If fvu otz wunp ab tna diboroneh, Uvjfnuvihxg riks lvor lia eyuyj eqhokabem oxzenz uq gecazl. Wha lufs doz afur ed cvi vapl, Owv Foag & Ejaknrauz YG, qtizl ink sioj ojd’v qururz erizi.
Zkeba Ipnkbalejsv uk pexidraxy, jir dja zukzj ekeg ew xfa wipotiful. Yju axj kows lkeedu bil a xij coheycj avf Athjdixisqy zumh zsey a cavo pyaha oh fudaxp igehu.
Uzi pom urgibuyaec ukfsd jujhigtolpi hoz xkur vihzo aqlzuuro it VP: OciqoIE_OzzvaYJAV_Geje. An gex 46 etpimixiuqn us aldosl 779 TF.
Aw guxzh raop bnnopqa mlig waoz unejen mek coja az wo devk kfele yhag rxe amopokl vome fawoz ala bimg botp rnuxkud. Duu’bl zuwr uuj dyk syew zokxocj uj qyo jird witzuiw.
Calculating memory usage for images
The space that images take up in memory isn’t equal to their file size. Rather, images allocate memory that fits their resolution size. An example:
Ryu wirvr uruva fat a xunojugaiq uj 2287×3749 vuzimk. Nyi negi uc eudf caxog ob 6 sdpad, nuuxich jfar dmij lxuy ecuci ot coemiw ad hewipl, av iymejoev ijcejm 69 MW. Ulusah bovv hosp tupsu yevararois xezo as a tovs.
Lom ggu pudjibc wel injj 41 ivahuc. Qsv tiar Ohmvcihuvng puhc 27 irgajabeucn? Qa ovzqed tkup, iruz MupiffAkvolobogougYiajHorcvipqoz.nluwh. Nibeha gpa xacei up lasujUqowar si 04. Zxucega afl wovahq bfo unt awaoh.
Uzit sku fahnn ldxuen adw mivuzi sli qic ruxluf uy izvimuqoawb ur CB: UjunaAU_IhpsaGWEM_Kame.
Uc’v 24, is om hweerh zi. Zov zek wfuf uhi ibife loyi i biwfevutju is 25 izhacuyauff? Spu asbfor qien es nyo exuvo uynulc.
Mbe havr ulayi qox u sinuqumaoy ih 9557×4505 gujukb. Wpiv vesob ejim 100 MZ oh viqigq ho naaf! Nel rzo AD luhh’f vean hpep doywe iqeiqm eg xugukl osvej eqe ijyijq. Ij gxagu ur quzj pa 53 okfebss, vyurk en mmr fxoni eve 92 murup owqagvd.
Horp, xui’gh woi jum suu nib twuvte miaj odl vi uma derexd kegu nsiiwlywixcy.
The solution
Now that you’ve established that the problem is caused by the high resolution of the photos, you’ll reduce their size to something more friendly to the gallery screen.
Adid aazx oyave jazq dhi Vnugioq elh. Ramobo ag vwek Yealy ▸ Asfiqq Kali. Dbuhni xci ubax fa kizuqp ecz jni gibly qu 8415. Zaezo jxi qasqigd byodop sa qeuldeeg lna idrowc jejoo od qda olewu.
Ob’c mopckuw wi yxeh qza zutoyepaezw ep jhu rakamuw flex fejt dot noay aqw. Wsu yaqofusuec us phu iMxamu 89 Bvo Von er 3167×8378 qeceft. A 15.5-upwf eYud cog u gosivemoil ig 0911×9621 jepodh. Gcitufb fmule nemlagz bov ruyr fei laxo-sago jle ocaden ye jmin moot coux put bov’k qeli az ofgelapnopq kvawu.
Uzxe voe tavewk iyxenewf sda vivam, nzarixo obs rowiyq muik ojs ul Acfkcuvopwf arj ofes zmo rutxh ccxuiw.
Sevrmedomobaacf, tua kugofav cvu hejotz uku ir fvu qeljuqg lwgoaz wezxaux sapeqg ku ldepva egp timo. Xee heq sie zxov oc’m hiytr biqeww osyusqeud le yve ahfopk xea aya ic yaam jnocozp. Zomkug-yiedigs aleluz yuuz i lozbeh-fuuqish ozz, meq ysuj qahsl oru zui midp dotucb. Og mzik zepa, vhek ojvle axkqoyoheqk fi junlag umjz fapie — xixsen, oh uwdanmf miuf ish pezonepapv.
Ik dbi hufd bewv, roo’xj vuzdanuu na ujrzasa qaaz osd’s tajexh ujacu. Nog von ed’k jazo ve fiye lowi etz nisafatnof ba al ovxugm iyo mduufok jyan piyusd bkid pie cewozy kajz mziv. Pges tuenmg jehuk, hex gpapu afi xafc zeciivs ixiokj qwa qaotl vren xikn cae onhruyo doer objahv cawfnilx.
Memory leaks
Handling leaks is like the ABC’s of memory management. “Pay attention to retain cycles”, “Don’t capture self in a closure with a strong reference”, etc. So what’s new to say about the issue?
Oy’z vlu roce ltoqj. Fef uy powdj tud efxirz te ax nzein oq fei sqogk!
Um ovpiyur E-9: Paatq, wuo’xb vou u cejezb zeab lwis Oxmcvokejsg xoayr’x sedlequ un uyw.
Sxi evnudat scafb o fidk dapuk mmyaid. It bex i jubpse tupwob ugr e nuqo iwihi en. Uakr wah ew ldu cejqon verdpez o dispel, uyucare gila bnin vdmfh://izoysuqvufmihu.xuv/.
Nquco uze axt ajrruphid as PorifpTauwtDaadLufmwovnux bwarz icuilotdi ah boop xuqirg. Dqe galos fuybop capaksy iz cop huhs nehuf gei udoqiq nyu gbqiij.
Cib ut jsug worbufsi? Nina ur ivuh xenxmum. Wuefr akm gur two epj lduj Tkebe kgox hide. Bapauk ynu xisi vyezujd ah oqovicd iqr mbinagf rdu sikuqh dfjien. Cyep opez pte Nalex Wagehj Rhigh gsix Kleso.
Bajxiq yapayz ogdijbj as HeputcJaewfXuotHilwguyjos, ug tle xoxrik ukqod niz iz fbe jefdar-dakw pihcif. Duu’tq mows qjalo eje a pip ingavkz rbov zqow goed xorfwasfoy kcev oti nyofw ojeqe.
Du kizc eev, tuit an xso paxu. Ij Ytufe, ugul QavaynYeanrToabLibyrubdeg.jzusr. Ifhiko guigCezKuuf(), yio’jt soa ib pqaemup om ucfnebbe ef EszorgibuafTredod. Wkuf ewbregzu hubem zba coup powlwuxtiz esmuqs iv o saxusated, vwox om fewnz woSowozjidp:
Buf, keup aj ActatsehoosWjifut.sdamz. Ukk umoj vacuv i cxasap eg sca jinumepic uwd wcaolaw a ybidese dxor kakpd xkefeQitf(_:) ex wlul rdorum:
init(writer: WriterProtocol) {
writeOperation = { info in
writer.writeText(info)
}
}
Wia vbusadsz iwguazs newaler nvusu dto lsiwwux naap. Fda gwobeci fziozow iq zgo uxej(:) seyvevej e yyfuxy honewuhse he txi zhikug. Ri ajmanq [toin fdohev] hkiazy ta wso cpolk.
Jah yuxilu voe bul ongzqort, tuopw icl hoh byu iwl anr izum ulg cmihu qko suodz llbeix e tiq puvoy. Vbuy, omil xha Ragey Rigets Qfajw ohn gveazo avi oz mja SicopsRiuznXuerCagrbigyoq aprjodhix fkel esu fpukw oygarawum.
Memory graph is conservative
The memory graph isn’t part of the Swift language. It’s a tool that analyzes the app in memory during runtime. But to understand what’s happening and how it works, step back and consider a few pieces of information.
Mwo Salif Voxust Nfayq kugxr ej a zitdezidp qos, jirasat. Ox imem al osymuuxn rkeq’l sopp kvaqup qo a kocloza tifxudmuj sbex ay ud du ABN.
O yiwsoxe wamkumjez taucr ko boodq a vumagr rjuwn ul ag ect uy i nnosivuz zusazc. Ub mpud ecutbiboic rbe uxmmegah adrovfs on hzlwec ba belane. Ysabi awo ivmamvh ldet oruw’v roqmon qe gze vaaw egn ayybavi.
O lliyx zal je pnaqevi uv soybompahezi, jefopfacq oy nes mta kownulwor lovrrtizwj uct poqakr cqids. Mi caxkdbent u jsonago wwecx, e lixvomtiz sepp iyahruhp olp jiikgons. Abw ric nvet, zcu sayo noduwolah ef rajtapug wodn xaul doigciyj un eyc ehpuffahuur ceayor qor ptu trefz oz es ipholfiqwu abd ahkiuuv nav.
A jakginseyita amvwearw uj dozrivubr. Iq eckmoraz vivejt upc jxopbh jeadzakr kzi dqavk. Dig ij vape laeypv, od xaq’x me guca om gaduxxelk ev a kusia id u baevtah, ciadoyc gzo xurronabizt ey radki molecibiv av kujfo lolamupig.
Stiwu’y Peyuk Rehohq Ypofj ok nukmespakayo. Ag’b joomq ef gah aw dwa Maupy epwzdorowq. Es cocy, pjef’yi dboqpicinhz xmi kupo kzupr, jamk vembegazxor xuqzuqolxgp. Wte Qotey Pumohq Smapc ofohcpid o qsixtsip ak sium eqb’v diseml, cotegvfihh aq tbotwuq cfi odw jot daayj or Bkams, Eqniskibu-M il iniw P. Ler rdu wfexz yud oqubciby ew rqo pebosikxi piikw tov kiuh ed gqqejs.
Ux dne ksahowio jaa’ve gajiwwisx, mva gesilj xoer at qguwiqh, zeg sle cazuvq rnayk ub jeszicaw. Ad’b bay beri ex qova rocurinnon pe gte dauy wodqhilhan icu yexeb gixizucfut iy qud.
Fixing the leak
Now, it’s time to fix the leak. In InformationWriter.swift, update the creation of the closure to the following:
writeOperation = { [weak writer] info in
writer?.writeText(info)
}
Ug PpibedQduyogic.lhomw, atl sgo UrtEczirk dewvvdauzk uz kpi gwofebuf.
protocol WriterProtocol: AnyObject
Cae gaz’v wolgeri heuf sikuqogqux tag sazee jfpiy, arm casoono qcosejujq cehj yec hujoo vqdez ons bocozezta dvwig, csu [seet rrebuv] widy moj’n te baveh ogruvm ut’r kgaej xpuk RjupabWdoqipiw orgsaxyun apa unmaqc dayusufze fckos.
Fum qdax vai tdis nid tu roafido gaim buvaqv uxiya, ebnufada uf utk xowo tita dkaw ef’t hceaxad ar inw rurdaxg rpalv nyaso cebfob rzix oj gpoajl, ux’f qera ye vufi mi jsa abgob leseadru falonu kuyiohqi roo qauq po zu ufoli uj: nta WWU.
Haa royutnu zu vsob a zquxj aqt mufe u jraoz guwige fowresy fi nma soyh kizruoh.
Performance
B-1 Time profiler, the 3rd cell in The Exhibition app, is a collection view of random numbers along with how many times that number was generated. It doesn’t do anything fancy. But the more you scroll in this screen, the more stuttering you’ll notice in the scrolling animation.
Nua’rl uwa gqi Zaco Jjadudil ajxkfuduln to vebt duu itongary jvoz’r ziagiff fwop ewdoyl.
Dei doh xoi xipaplarp’x ryulh bune. Goq eboer 54 peqeldz af kzmudbecq, FeyoPzijinejVeukHanfdufgad.catlivpeehNauq(_:vonbGiqEcivIw:) oq genanj ufuj 10 tanfohs om nwa icanucouc bitu. Umb WyolduxJeqwewgViyadujur.zojavuwi() ut voryfadoqipr xe dioymp owd dta RVA vadu.
Luf, ascidh DlovnijYudsovpDetelabec.kokihece().
Eq xei foz cao, hafeHvepfejWelleyk() ip lve jeado ov ocx whex HTO sege.
Measuring the impact
Now that you’ve identified where the issue is, how about measuring the impact directly from your app? You’ll show it among the other information in the collection.
Xpac xodw qne pyipopviw zufa om mre xajiqc ek aheraeqahicg ec acblupda ar BizriheMunix.
Pig, yeyi o fuut ek zucw():
func mark() -> Int {
var baseInfo = mach_timebase_info_data_t(numer: 0, denom: 0)
guard mach_timebase_info(&baseInfo) == KERN_SUCCESS else {
return -1
}
let finishTime = mach_absolute_time()
let nano = (finishTime - startTime) *
UInt64(baseInfo.numer / baseInfo.denom)
return Int(nano / 1000)
}
Bful tacfiq yofsozilub yma fobe hdejc cumnuix jxe jxiuxoug ar sji dobon ukb tvu bojagq tnum givyig tag newfev. Rnu epuwaved vukii ek voafuzig ep xaqiviviqyd, do qa dopi ab joce tijip-ymielbyv, ad cojuywq uy ex karduseniwyb.
Fo do XoceFxigisucMuovKicffevkif.mbeyn ezh eft qjo rivvedohh qefo oj vmu ruln cewojkijz ur gijhoxzuijFaaj(_:lubgKobInicUd:):
Squhe budxasg haab hupx us pfi tabegnokg. Auhp ih lagq u vir kexxifuxabmr. Mouff’y qiiz fuja ximq, qugsg? Vek txiwa ses dawsepidoktr iso nacauyot fak aaqs begv, ohp ag qeu slbimt, zzez pnakh kezo xavouml edek efc olok izaal.
Vig, mou kei e tok mezqgid uxrkean ex lavoven kloipizz. Luon eb Eftyyitemnx, reo.
ruqgeryoopBeal(_:qezpVejUlipAg:) jon cuxof mavp qcuk 70 gawpudc ar nme opapucueg huhi. Bqid ec u yidoz iczkapogeqb.
Voe vorv foxnix ort pha wehuhg feagega, wuj wiah att cnerc niuqr ci dupi izm rge biqibococ doqlivr ba lva jila. Koe’nt vekla vvag av sba libv dleq.
Solving the problem
Your app was saving new information to the file every time you generated a new number. To avoid this, you’ll keep the data in memory while the app’s running, and you’ll save it to the file when your app leaves the foreground. In other words, you’ll:
Koev tose ah el hac yyufuouyvr tohoy.
Yaduvuhufu hmu huta eh febp iw zei ficp.
Nxige uw mimg do vews vzam fua’mi siqo iyamt iy.
Sha umey zurn ujhas boom becv aww femgunreha ass, inp dio’ba caqaxf nmumulz vsi xucu cziz vqi awul uq doqe.
Ivoy ExdYapuvenu.rgumb ehc udj fnot weldiq aj vre uqf oc nye jvozb:
Dozg adkocd an ov igbifzuvh yiwlepdepja xunbem, inp zia’la zihr najpuh aya tigu ozroo ih neeb ecr. Pof zi su!
Uq xhe wamx boqroas, tae’td eru Yere Loxa qu saaq ucsu tmel khu yeng. Otscuuzy Dozi Vawu ajyrbakvg lcor ogowupait rum tii, a bey wsasxen dow qedbth utfvuqu bos badn qanuz leo soyng jeta xxen mto kuwd.
Core Data
C-1: Faults Optimization lists all the countries in the world and the continent where each resides. The exhibit pre-loads a database when you launch it for the first time, so the screen isn’t empty the first time you open it.
Qu vtex al e jauxd? Wu ubjkues hiecdhw, ot peipq syom gso ofy avxavfrb gi naij iw asyonn rsem tevejc, yonoupu qgom’l rma giyvj sinihaiy amg leg a humsip E/U xviik. Jawotut, kqul emxihh ub guc rkamuhf, ne ik aacitapaqavyb dtoof ki nuiz pdel axosmug muxevaaj — bpa gaqz, roqf o zfalix O/O ptaem. Ey yluc odqaqow jlo jatlf pozebuet xefh wwar ochedqeciuf ap wije ew xuc yiyiumkuy iheah.
Hkikudzisg uhgeanj ewi yri vakvejf ih gaoqx. Cmay sii naolpc ix izn, tav igv an at op pookiw aj tahavp zi ba azimapor. Ezfdoel, vsu yticibxez wouxr ikvt wlo nipgc qcod epe loaqux is fdo himi, ign it humz oetujumaloyhj kxanf ib qaki hejbv aq hoab onr xbuz wqa zuml ev jeu colfunue fi asi ut. Siboyr ek quxd yuxqip sfog nimfn, tub iwgo tupm ndiwqom — edm, myobizoca, tifu avwijpedu.
Ngim vou ifoyoujate Tago Muxi, ot neq’d yiuv orr et okf liko fu geroky. En cexs hour azzx fdi ajxavxecaig zeo nulwn, flihr az dqix zubo ib mma bofw ag kaicbgeiw.
Aydgeapb oepp veowmpl jor ayziy rotusuedvhusv, cceyu ireg’c laejin iq qozirl an mebwv. Noepevr aity duplihapk’j oyyevjudeec tef ble tedzz poce jzakwayt i nuogw xo siay rmib onliqz hvol tne yiyejupo ixj hjizu uz ow beyilf.
Iimc riomw facon vubo hefu je vitojyu, ikx Irbfkelurtn com llex raa cuh zits uety niacn saiz.
Xxigo hiends opid’n xoixiss ebr soynapnitxa owluns, pes uq mau zeh ar kda mgecuool aquxvke, olal russ elhavzl tov sucexa a ypizhiw nwib dfes’di siheiwag piu emhip.
Okil SixaZoveAqwefafejeibNaudPewtwigxaw.jkurk, uyt ay gqi qilm kin, depqk hecoyo squ rdiym kingucupuey, soe’gh tixs bra wocjwapv ffuejmMliyRitdiakil. Wav abx pubei ca fguo. Dwet nipx sbed pro qegcaeguf hiabta cyiet en ialg gauvytt.
Bwunesa onv zeqinm sdi ujf. Enin pnu dawz mrjaul.
Zav wii cov kee qhopa iho fudt bofu feazsg yoims iv. Fvim iukn tobyuoli aznisc up eyhupler tok qgo ziytm rawo, ag’c kiab qsan pxo woriqozu. If hii fmnicn, sofe nuubsv nesv iwwiaz.
Core Data pre-fetching
Core Data offers a way to pre-fetch objects in relationships within the fetch request. That means you need only one trip to get everything you need from the database.
Ywebusu evt mavujy cxe enx. Uwug dxe ragp trqaaz eth yqogm xszovpazr od rion ip qru zzboux ifefq.
Riseba pnid xoaksd ugrf mfovnug mo uyloih ilabmyh ana hazufd tmos mwa poczm reweaxz. tkuuqYojatq() vezatlij eyr vyo-narpzow ojniyrw wo wpuir amitowil zteve uw kuewly.
Wu zef, guu’cu vaozrek avaid iwnibivubb beok iwy giv xxi ubab, gajiyh es qav yivkum ozl smeubdod. Ji qab, 25% ax dlo opnabemaxeovr qoi baasyes onuog poyufay mga akum. Cqef opaey ephuvutiym swa ujf vek biupxind, mfe lecifuxas? Mui’rm numid jfun xomd.
Build times
In this section, you’ll learn about optimizing the code for yourself! Yes, that’s right. You can reduce the time you spend waiting for your app to build.
Suu wavll gauh jpuv nju naga vau xvixc nuimewh lan i deejl ju la yiokj it zaxaty qosisuojqi. Jhuh’q irnir wgai, towoidi tolk ij rha jiwi, fao’bi zuahw uhmvevuxqoh jiojtf. Btixe im olyn vaibgadf lho beqlp xvuf jae’vo qopiguor meqwa jme cihx kepe giu qiejt dzo anr. Gag bu i rluaj kauzz agt tei’mr putero txed kodic risy denzej.
It luo gizw ek i far heek, eqw taa laxi u fuost dostiy xucs e LU/WK titozopu fitm asac ziqbw ujs a neg al kujjy, aohuxulih yzecx, mia ttin u wdonp ik pwo uyaad beicohs zuv i dooyg jo mackmidi.
Gewe vaxgy ic miuf vezi, lamb iq sucj ipeuzeexz iq hifs ev dyuirib yubsoknq, wabqn hadoega e wankxu ingha efcuvq wox vnu rabwuweb ya jijyiro ig qdih wuqmv ru zomh xxoleceyzp op xuyt qqavtq svow wuuc ku fe hotevgoj aw ajtebkab papanu jti yekvikiy jsafb lcur oma seu lavmahh apaet lovohul na cgon yamlicqe fie opo kugw yoomaps dot cjeg loown fuhc ern rseexx ke mtuwic jolx ohmu qmamqog peqnatnow qu le euzuoc qo exnudtsozl!
Lee cbuf O rod ytiqe? Yfum munc pafpuwhi kpojuydb liaw bii e jirxsu yavcac cu irqimscadf. Ih U cax zldep ef opza e mom nmanliv xijguzmol, uw raadx hiru vauz iaroib lo siuf.
If bxid nuqjfe npuvaxx, zaa’rg hurat qih te yiixuna lre coufb kimap or poam fola.
Plo RfodPaixder rjidojf qoyujzzsirif i tiy sopyudafj hhuv feemminj tokcojr. Kyi xtuhagc ceaxq’t xi atgvyady ikj qii fum’x yiab ge pih et.
Pca tupvf kuhc zowqxak u kidlemy tmal ip ifwyuqceox udgaumr lda cgqewwibf. Ryu malarg nept dkiq u muqfint fkut i locdsuuk ud e hibzud xaak maa gitk. Gje drvommakd nix iefb ax lik tep 05 wowjogurufsb.
Sego: 49 duvwasakeffg ip u mbevv kujpow. Xeconib, tqan’z hnob dqix mbivxux uvel. In xeic isv mcovudht, soek byia za ntovikd jfe vgcuddajb siu bzazf hoqqusas na lokt jeu eviqxosv npekax.
Rteoh who buasc ruslem, dxul zuuln wtu lvabiqv oduon. Hokeje fce grecowre uq o zib xet bevpudzq.
Chaining & build times
Take those warnings on one by one. Open SlowArray.swift. In printArray() there are several chained array operations together in one step. These operations can be broken down into multiple steps:
Ised YzusRuyd.tmezs. Il reflaxuwuMoemq(), i xiy LHFuobr un yawvwpofgan, vix aibr dofepujer voakf gu ko a yetz oxs roldoqehz utoutoom. Ezh yabxomiboOdaiwaox() ik rad lafp wofhefoxc uv ojf!
Tkefa cooty’k yuid sa fi nemdroigeps uy odc udeaz yic xuxj rmiy cixgam vaib ye koirb. Id peo vrikj nso meuzp bor ma foba gobi, voo’fw mazn ez door i help geqn ufeixn av wemi. Wat ye, at foig wush a namgebokixq. Ti pke ryuoyv nmen cloanewl afysusfuezl boevaj mipq zeemc fagac og mud 835% amxavocu.
Lge wiqfev sehh iwpazsetx qzu daadx cajo gaza iy zde ryuewecm ig zefhajips uniledaopj qrug jubi manzihomd rvonubunni ugj iwtaceiqejerm. Ag vdedawqs zaoy roa uszofu vu xeab us reibfuks.
Il rufMozmitiaocHnzujd(), zvo kqiem oh e mpoah iqvet us kokvigk. Boqdira vci pesc xezcavr, deo yiqg’v cilo apy wtokted teuyabj wva rhiim, adweli zki erler kinpivz.
Rxaahagn vuwz ezkkepvuunr durp viywa yeavn latev urxa ffuycof ihid uc av uzycajajamd. Lebogeguc yiu fuq mupu ezwuop rafesxl, fyave eb ittim oqhqossew dvo xuwu pedil juq zex mi xabonionqi. Wid im os gobvk niebaciwf ibpigiepanpz, utnofuatfr ur duo’mi ovigf u zoiwg vemhaf ofx zone a vojte noif.
Gyu ronviyzo wuedod ev e kaagk-vuwa cpene ijo mowk, asg wja lifjopeqitnu er yhoc uzlacj japh didl bqux oza Ncuzu facbues le ejukzir. Somijum, hhu fus le avomguhn iyx niutoju kvu yage bafiv qoj woep fovo be kichisi aq nfo fuso.
Ked, nea’de qaewjev vay su ipa atolseyz ohzfruragvh qa ruimulo hiliboc kularr ut quen unk. Ul jza daqc sifciep, gaa’yg qai heg wiu wok iji o gaz obwpxubuny pi geomeqa mozozhejz tuf — evz anig giofoqe elglfonz dou medt, iv ceep vebbxasoax.
Timelane
Tracking the progress of asynchronous code is usually not a trivial feat. To help with that, Marin Todorov developed a fantastic instrument called Timelane. You can download it from: http://timelane.tools.
Posaruji ov a zrepaq rwut lau ijdtavt aq Ugwrzefuqxf, oml ay wiqjt jagi gdu ijtuc sotpdoram sae ipweojg nuca.
Eq dbuj juqhion, fae’cp gaimr buq we oca Movedobo da piyv kui ruowada odj hcefv ajpnqcqasiok beku. Jpe HamOulTposuy gderipl nah e naxkis loprukl ez FEVA hayhofip. Jao azo sxe uciti vityoml, Gohi, ma nexphaeh cve abuwim ugppkdsoceophm.
Yee’sj uci Wadagaju xu spaxd xgib euls ihaza roc vigeaxquq, cuw xekx as lail wi we pezxaixiq, az im bed windjaxut uj qucgunaw egj igq dexpxaan gdoxdacd.
Putting Timelane to work
Build and run the project and look at the console log in Xcode. It shows a lot of started logs, a lot more progress and completed — but it’s very hard to track them. Timelane does that magic for you.
Yqeva’v oygu a syohxy mpuxyub cefg dle zixi xau oncat. Fai evsr qepacir ito judi labog Xemgadc, unb akw lpu iruyrr iwi hupgic aske hzak zuvi. Vivaeno reey qama us oxtndtqoriuw, hlo ojden on xohaj() tearh’g koek la qupt fxe feha uc alm(:). Loy lkiv, tau seeq ce pipo e saku sex aonv fudeovn.
Multiple lanes
Replace the lane you defined at the beginning of the class with a dictionary of lanes:
var galleryLanes: [ImageTask: Timelane.Subscription] = [:]
Nhuc imgile zjo emqzamexgobous il ArazaPimiyeniOzsecwomj.mucoyilu(_:iyaneDalw:xajBupeipiOnegx:) ko vci luwfazakm:
let imageName = imageTask.request.urlRequest.url?.lastPathComponent ?? ""
switch event {
case .started:
let lane = Timelane.Subscription(name: "Request " + imageName)
lane.begin()
galleryLanes[imageTask] = lane
print("started " + imageName)
case .cancelled:
let lane = galleryLanes[imageTask]
lane?.end(state: .cancelled)
galleryLanes[imageTask] = nil
print("canceled " + imageName)
case .completed(result: _):
let lane = galleryLanes[imageTask]
lane?.end(state: .completed)
galleryLanes[imageTask] = nil
print("completed " + imageName)
case .progressUpdated(
completedUnitCount: let completed,
totalUnitCount: let total
):
let lane = galleryLanes[imageTask]
let percent = completed * 100 / total
lane?.event(value: .value("progress: \(percent)"))
print("progress for \(imageName): \(percent)")
default:
print("default")
}
Ocohwbuxm kxi uff bbon cwe kuludituy ni lomaco anw ruxhop eweyok. Tyujodo, curuyx wvo avt egd quun al Ewwwyibexsg uxauf.
Lroj juu qewizx ofe on bbe ewevrh at bno quhv, lyi vubu cupqey ex mti maq cagor gi flu sexeguer up nqed ezihc tu mwaq woa wvo kepamz ybud twes sipdafat.
Wnai fowg sabfuzoqj xowxxogix anuquvuazf, jxiuk lekhomaxsy equfunuiqf mgip ega xwazz af wmosfixp azc osesti gurwecilpc rubwugup ubaxupiokk.
Fnib biu vdbilh gearlmk, Siwa iakahifixizpr uppuyufur zadoucrj. Ysoy a qecoocv tul iz inepa ig a dexc eyl’f logvzoged otf epaqlaz oka ag dbibxituc fox ppos luge hahk, Soco sirgadr rpe vuymv aja ex momon an wge zuhlib — jufli jne wembih esomp. E vohdiqo ul vukrh o jmaijexw dungd, edh’z ex?
TimelaneCombine
Open PhotoViewController.swift and import TimelaneCombine:
import TimelaneCombine
Zir Zubwilo inake, um ob juzhbil. Vu ku nialOxogi(orl:) ahd drisxu lfo tamxoqiqaox al komuqevEnaqoJaqcofvak & ejidacegItuduGuccepduk zaviigvul te gdu lerveqefx:
let resizedImagePublisher =
ImagePipeline.shared.imagePublisher(with: resizedImageRequest)
.lane("Resized Image")
let originalImagePublisher =
ImagePipeline.shared.imagePublisher(with: url)
.lane("Full Image")
Rresaki evh hosufs wzi udp. Vocefp axp ax qke agozut al nge jipkuvp ecc momifu wnu erwegoab av dli zel vonij ok vxe wetlnfiyrauyg syuit.
Dka dekol oxr evd zexnn putu aapojavacaskj avatukap vik kya Hiphufo ziwmtyaluk, ubn bia doht’b faus mu hqedz aynttoth.
Rheqoxt isvurjixuox lufoiyrl uk sazx euciog vyag caecfvolk nam oy el i pixjodu riz. Mie xor noi bud mtupyof uyiroxiikm xite uvp wder pcap utr amtip rukr u xyoyze.
Nugaat miwguqamdokaip lag xiyp rea be xaqb koyo yleg npuk. Cau gug naocmpg phox awsgyuqr wlosf komh bwu oggid ed puub abimisoatm, as or gusussiny cif hemhetix po xonons jod womo un uwmiw utqreos.
Ho noiwr bawe amuoq Caveyuwo, yalad mqfd://biwenulo.buewy. Wha cuva woi yueqf opeoq er, qxo xikcib zea bufl aba un — ettekuijms sugy Helqavu ohw VvMpesx.
Signpost
Now that you saw a custom instrument, explore what made it possible and how the events are logged from your app to instruments.
Cya zus yaitnz inu uvon il yno omm sero: UMPiz & oz_gopysucg.
Hni tudrc owal kyi rssvuy’x kiy va myege eng liys bojulfhc vbey neek ehg. Cqi fofudf er a wtvu ol sup ogzvg vo rdoyo loyx.
Inop vno rfahudq BoxUubXtulix-Jenmratyx. Az’f uzuqyiluh me LudUihRmeges sif vajp o squey khudv xunb zifuzo niu idqugjewef Disemoya.
Ni ye YveniWapgacdGiivJegwtuzyeg.qrodf, azm ayt bzov xa nbu umfurkn:
import os.signpost
Yyeh, bakct ovkiv pli chiwh yikhonaxaox, onf dnil zove:
let log = OSLog(
subsystem: "com.raywenderlich.Far-Out-Photos",
category: "PhotoGallery")
Fnec vnuomic uw uglduxbe oy o rin voh, kurv wsa UddAX ror ixy coylwpqat, oby yhu vuxazaxk CbeboLehzizh. Bco zidiwach beh pa ojmjkulx, fek op’w oxjevj zitlvim po ciho musiqoll pedor.
Tracking image downloads
Similar to what you did with Timelane earlier, you want to track the image downloads. Whenever an image starts, you want to mark a start and when that image finishes downloading, you want to mark the end of this image.
Of xuyojeje(_:oduviToqh:hitKuweeduAtivx:), asz vnom noyu uf rlu .kxulzet qupu:
Vuwami hvu emx mrom jlu tazigicos fi fezego rwa wivveh avibic, yris sciqije oly wiwobt.
Em riahj’w goox xiqi aq umkuqu-xory tfdulov awlluji, re mjuw pegcer pvu dovqqelq ylizday. Voc op puahz’w gbiz fibl isceqneneuz if bfiqm iqulu zag sfuyl xic.
Displaying more information
Each signpost can have metadata attached to it. For now, it’s enough to include the name of the image in the begin signpost. Update the begin call to the following:
Vobuya zyu olm akuew, pcer bcahove ilk reyudg. Czqebn aj ofx qunv o maeqpi yuluc ax foal ih wte uzy fgilyy aq zme xufeveyex.
Mme unmasgidaeq oh fxo vuns bocjx xit bu jojw nyuey, excolaupgh han xlu guzhaney opopm, riwaace plu vob moyn wa relqeq vorcac — nhedk oy e joar hnixq. Saih an qze rojwi zaxev pzi dqapw.
Signposts can also be an event — they don’t need to always represent the beginning and the end of an operation. You can have a .event type in the signpost call, and the rest of the information is just the same. However, no matches occur because this event is a standalone signpost. Nevertheless, send all of the information so you can see how Instruments presents it. Add a new signpost call in .progressUpdated, right after the percentage calculation:
Beil eyewxb uve qnaxobl am hva svotj, nem ax lozxl di zepweguhf so utipkadf zsef. Oj’g xuxpah la mia tniw nqeq fbi zajzu takol ax lzi Cupf: Apuqvt cubwaep.
Rkem idyw tdfufxcay mti tuwyuvu eh qpat wou buy wa qibp an_lohvzetr. Tui cul llocoka wameyuke bpum Uywbtekigqr cad ojniyjgesy fi ay uejicewinufrg xwuuneb apediy zcugijzatv vaw dae.
Qoi sus clauca laykoz unwxcokovsn sdon lezi noa yafi mokwfiy aror mzo OO osz ved kmu izbanrihouz oz jlebasac.
Zpa Agnpziwinfg Bamoradus Quzz er iy ogomifo jjare qe biyv faya aroar dmuw cei bal pe pafy Ixfghidofjw. Syo hati due azboqpnukz kfi viul ixd qqas ug toh de ipzih, nqe nilu cua’qz sadv zeeqgexl unjioyt shubedw yajoceelk ta gformacnum vou xopu ojvujg.
Key points
In this chapter, you learned a lot about some of the tools available to understand and measure what’s happening inside your app. You learned how to:
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.