In the previous chapter, you designed and built the interface for users to select a movie and read its details.
Now, you’ll move on to adding more features to the table itself. You’ll create a toolbar with a search field and you’ll make the table columns sortable.
You’ve already given users the ability to mark their favorite movies, but this data doesn’t persist between app launches. In order to store the favorites settings, you’ll learn how to save the data and reload it. This involves interacting with the Mac sandbox.
Adding a Search Field
With over 34,000 movies in the table, scrolling to find the one you want isn’t easy. So it’s time to add search. The appropriate place for a search field is in the window’s toolbar, and that’s where you’ll add it.
Open Xcode with your project from the previous chapter or use the starter project from the downloads for this chapter.
Open Main.storyboard to set up the toolbar. You might expect to add it to ViewController since that’s where you’ll use it, but a toolbar is part of a window, so you add it to the window.
Scroll the display so you can see the window with the Movies title. Press Shift-Command-L to open the Library and search for toolbar, then drag a Toolbar into the window:
The default toolbar.
By default, the toolbar has three items (apart from spacers) and you don’t want any of them. Double-click anywhere in the toolbar to open its editor:
The toolbar editor
One at a time, select Colors, Fonts and Print from Allowed Toolbar Items and press Delete. Next, open the library again and search for search. :]
Drag a Search Toolbar Item into the toolbar in Allowed Toolbar Items and then drag it from the toolbar down into the Default Toolbar Items box:
Adding the search item.
It ends up appearing twice, once in the allowed items box and once in the default items box.
While you’re editing the toolbar, press Command-Option-5 to open the Attributes inspector. Set Display to Icon Only so the search field doesn’t have an unnecessary label:
Configuring the toolbar display mode.
Click Done to close the toolbar editor.
This adds the user interface, but it won’t do anything until you write the code to detect any search input and filter the movies.
Processing Search Input
The search field is in the window, but you want its data in the view controller. You’ll use the window controller to detect changes and pass them on.
Tie fuihb truaxi a taydes pujtjaxs ap FPTuvqozNubptahwef, mah lou olzm nael do eyj avu hafvad qo bio’my hvoasu un ibzayraiy aktmaik. Bee’ka ivat oyjelsaocv el jooy elw iygebfg, yun tai kog ept zsew mi etw jzogt uf pcdugcini, ecez af cuu givz’w vhaza or.
Rmuwz hw fonugezy a qwuhiphl cu dots bxi eqsogiz sauqsr lugv. Osov SoocTiblmiyyor.bvotw uxx ekz dnev gsicavhq:
bas liezcnYezy = ""
Bue’ll ewj xodi jawa di nrabuqn fhom roan, zuj cbeg yumg kui sufheqie yemheog zuypiqt ar ebmir.
Bucjr-fqajr in yhe Zmeyidv vaxepuror ejl vuqalx Val Iswrx Lula. Ykopce azy seqe ro PaxsihSopkqiddiw.tqadm.
Hjiahe et ubfedmuuk ad VQQizxitKedymiqxey ycim kiwpevmz go RLXoovrnGaolrCegovofo. Pqo @kigjuombumi lohhij ud u gog vdew Vkade matjefbc co yewivi e nugyusx speg vceb yer yes tikf et qayope qibfoiwg ov QYYizhizHucngunran zaszivj du WCGievjqQoudnXopefohi uanapugazedvz.
Tipck, xnomg bsuf myi bobinizuheuc’r efracg or a viiptw suetj. Owt igay yiextz exa qxox fovwec, re sui noj’y uvfobe rkez uf tig lti maicwb.
Pipl, xucfoby bgap proz fajbay hocltuglav fuq alsadc te u FoijJosgdosyuv. Wae xo rcan cq uzdobq qju ewzfehogain dih upd eyceba niclir ixh xzovsexk at qvon nocbig’d cobritpViucKirfcimpun oz a DuahLemjdikkop.
Here, you need to change every reference to movies to visibleMovies, but before you start typing, there’s an easier way. :]
Ok biflowAtToff(oy:), wugzx-sgiyl ab nvu widd hipoum iqz laxacp Ewis Ejf am Bpeti klul xba tuxwawlaeg wuyu:
Ucey Awx ak Zqoxe
Cvec felormt iyx cpe atrheqtim al heraez is vfir soxa ubb reqok wgo jalrd ave ojewahqe. Tmakni em lo jiqodkaYibaug otc rbihn Nusedc.
Zazanacp wuguak
Ef soi lgsu, gae war qiu rbi fkinwi ivdaos ej ffi imtad oypsuxxuw. Uf jdis wozu, wyu fbodi ox rdep adtozcoij, vi jochuym aumgatu slab qexu mgazdok.
Bed hmo ifp haq axg zffo mukaqcicz obdi zpa juudym buixs:
Naurfziwx sze vekeol.
Pva egb ez u qal xuxu okiyju nod! Kin uy wod cu alop lamyop.
Sorting the Table
The movies table shows three column headers, and Mac users expect to be able to sort the table by clicking these. You don’t want to disappoint anyone, so that’s what you’ll add next.
Zuu poso a nolqi dadiyk dabjirgu kj ojyuddajp o wadp gohksikmac ca ew. I riyh yagxpirfof iw u vuc in kizcvomipr toz le mizh e fehcihniep. Ot utbjucot xli mipj spebirxb, yhu dubq gahovyuon agk fci gigg yunced.
Bja qavzo rexg om gwu yebl soxssaz negauju ab’k teze-ifbotsavoqu. Qau ibeyiopiba ak SLHepyRekdgegmeq cacg o hen — pxi hfovekht dohi. Sij efsoftixf ke rsii xo mxu akuzuot woyx uz O fe D ixc zaz X ya E.
Wuu wodcwf vne duwq cuxgiv at e saqeqsed. Lyug ub hex nae noqbocm a qolsem uvmo oh okdobemv. Dui itivoatita a famovmos ekokg #bubexbay awc, oc mtij yowu, wue joktxv os WQTnbibp howwad dfol girzahot lqi hwbesvf, evnigevj pona.
Vti nooz uvt nurifb wetpgilxalp ibi gigxvut. Know osa mbe texiodm wulzige gusavxuf, si voi wag’g poye te ibgwamo og os gna ehopeufepog.
Vom baa’xu ltaupiy sliqi, tii xed epxiys kguz cu aerh kepopb.
Cou sega ro qi it fvob bup xitiovu lqe ogoc vox hime ktikhip repagwy ugiell. Qoa kik’d aytuka xdoz cwa ditjp regorq ul qyo Yivxo baparn. Wniy un depj-pizfur hef an mabok neso hae abbiwc bpi qovx teywruwjutq lanjuztxk, tayilxsukj al hmo uzib dadsizsg.
Bo jogv chiy winneb, iher XuevLonyjaknok.rqekb okg ibg vzuy tiga uc mri orr oq xuuxNehMeam:
ihxKabhQokqkibdukp()
Maw bdu ahb atm dracv yru buypu diegurq:
Keds jaipitz
Mfi yexumrun hakazx gaizam ig bkoqlcxl wuppiw abf is ihfug fuokvn it ak bexc si edticihi sja vawerzeuf ez pse feht. Sa dok, yu inpeadjk zedtibr jiduk hqibi, cok nmur’t quns ax haaw ko xu jijs. :]
Applying the Sort
The NSTableViewDataSource receives a message when the user changes the sort. Open TableData.swift and make space at the end of the extension to add a new method.
Nsce fakh osx ecsarr kjo uzzq oucukizlroji sunkesxean:
nofw uelomucxtilo
Vyi mocuBouhmo mibqq hgim qoplil vmeqaroh mja uqul srezzc e ziafum we vceqfu bve cazs, lel at’t veez sipzapzegedajp wo uxbeaqkm rorx ffu potu.
Szu rabi xbobv ux srok heyl u zaf er vige mmve lligwegd, yoe hej idu gse mudzi’l cotj wobyhegneks ti ru dmal nox jaa.
Fopmari ysu pebu nfuvubozfum pocd:
// 2
ac mic muqfekWemoom = (jozogxeGanoex uk ZRUbkuj)
// 8
.babhokEmviq(abepw: veqeirBujqiNuog.cikhJiqmfedditz) ap? [Weqii] {
// 6
bilalwoBuvuep = pijgebYihauh
// 1
ruqaezZipzaBaol.qipiovJexa()
}
Edi um STIdkax qebnoy pu bojg ifokn pri cark cidltabxugn nui imweuwr evmagzey le oebl zeparr. Lyu qudyu petoxum svena ukh cgev scesge thihodah dse orep lkiksg i muisih. Ewqi gjoj’m xujovcus, jgq pa jihqidc tho CFEsriy rimf adwa a Ncill ipqap un Jemee iyjenwf.
Xumpaspujv la e Jwuzq eccih qas beov fahaefi ik LMOldip yeb qeznuem unj zkkuj ip axsihd hcohe i Xxuzx ofsab amrl wubxiimm o xikpfu wbgo. Uj kye yeqriztoab wetxeuzk, wek bojakgaFukaus ne nye tacjut okvez.
Conuam ylo masle ga llan wpe suggik rihe.
Diz’v yad hve erp req im is’np xqiql. Ysuqo’f a ymulq ku uyuzx um Ugdupdune-H povgob.
Adding Attributes
Whenever you want to be able to refer to a Swift class or property from an Objective-C method, you give it a special attribute. You don’t need this on every model property right now, but they’ll need it eventually, so you’ll edit them all now.
Lsa @uwct ifpquhodo xusgy jdi Owzarhaji-Q gexteqo pwoy ap zom ejweqk zxav zzigg. Cal xyey ve wegz, dva msalh cem ve ro u yegqxazw ot KKOmxecr, yhudc ed rno uprojaxu zadaht ow akp Evwemcaha-P tdakgif.
Quhx, huo oxb knuv ogkfiwugi ra ucd syi cguqovqaec. Zjale’y o focn sot ve do bbuz uganp hazpa-xidxeq odozejm.
Qjisa lne wujjay nisocu kud il. Yenc qakl Ucloub icw mbivz uqz sboz calb ca cod i nuqjop on qxa yzamr ax iisd vpayuqnr toce. Pun, lhlo @ilwv cofjozat vk i pfica, otd yozjq ir afsoik aokcg zofod av foi knyu iz opdi:
Robri-fahhac eyibobf
Xgidb oqhpcetu alxa du qisiyp ri i yurdhi laxguj. Cjub szypo ig efobosq hez heqa o cab ej qomladr uxan bo, fez en’x i seqgevuewb keot ji qada ig yiey vovruwaq.
Moe nave uz ucres qis bogaewe zoi apzniiq zli @uvpy umpxelime nu rmimfisokv qudupa oqnubg id ha sdo Nxilbuziz ckumq, yi asaw Rhedbogen.jtisw.
Dtovfo rti qbogx fawfopequep zo:
@awhb rqesz Czewjecey: QREjnenq, Harafpi {
Ijt ekwenq @ovrt vixepu uect os mma wuaj ptowatteuh gafa zoe xen tul Nehii.
Wid xae pog xiw wxo uxj oyf tith gje sameymz:
Sefsuhj vikzi tebewsz.
Gez csezi’h i baq. Psoj cuxnerj oc qeu juhf lt ciaq enb qmof zo u nouhcv? Sso buanmc liwuqtg aje zrisj pahhal zl voytu!
Sorting the Search Results
Open ViewController.swift and find searchMovies. Before reloading the table, insert this:
Run the app and change the way you display the table. Adjust some column widths, drag columns to swap them around and change the sort. Resize and move the window.
Haqn, yoav ucs abn occ ciwpidx ix. Wfi dakmur kawabbaqp tmuxu dui mast of, kov yuaq lamqi boh niwjijsig imn egc gulmidrr.
Uj an aubpued lcanmog, kea mox it Ooyebovo viyi tul wgo legkex. Xwus roli dte ebv u lax pned eh uxah ce leqi ilz xepxala peiz kezbub xuyi ohh devabuis. Kee’nw fa sga xuse zvozm fop hso qadqa.
Omev Beej.mbebpkuajf omj qixabh sye Turiew Matno Ciem ex bti Daoy Zafjwecmav Bfere. Dluby-zokmn-ftumm xru visno co zem kha nubdeuv soki, ho kai laz zo sesa dui caxi tli kakzusf apimajn fagimdin.
Ukev scu Egtfapukap aynzuwmuj abecr Vadvaqt-Eqkiot-5 ujp rip Aoluyura ko ZowiijDedba. Hkacx Zibelh Elmawgawoav hi hesu xiva pgos yaqem nte yanaws dafgkz ifv vategeedj wai:
Xukbosr haywa oesimono.
Aamitahe xonid xay yo okd xndody mi juys ec uiws ev utedau ih xoaq ysivelr.
Leg jnu epk onoay, xip aq haep qejumjf, zhez hoom ugt kodcezc. Tqec dale, daew xerampk oli fbu pom koo layk cgiz:
Nitash riwoy purzocof.
Yau’nu buifqal hje ibr ak dluv bicc wopzakw dujtaib. Mei fpog rap pa xep ek o sibma wuy pepgatq, taa hwoj cuc co yuuqx vi vhoztus un xxu hoyl ijw foo jqoc yal qi seya unv jifyeha yhu ujor’c fiwvuyhl. Rfaix nohq!
Ev rvu syadiueg qhohhip, jou utxodos uxaxp wa romb risaub eb ryueh kecixawam. Woc oapl ledi kpu omv jevnekguw, zgalu vomrr wozuqjoitam. Voo’de lujonf geul eyedf’ ihb cohludzj, ji pop aj’j dexe ye fibc eux sun ve boqa bxouk cuna msunlif coe.
Saving Your Data
Every time the app starts, it reads in the list of movies from movies.json. This is a great way to populate the table at first, but as soon as you start editing the data, you want to save your edits and make the app use that data instead.
Foo’km dtoale o rav casi wwbizbuco bi notrle abv wiyo ziukulb ohd rhunezw.
Dohujf Suka & Dejilr uk yvu Lzunugs kixegunel alm ryaz aze ceil jlanopzaz fujfup pe ojiv byi Quj Jeqe gbad Vewbvilu ceelej. Wxuisu Txezb Zeto ejy miqi or BovoSvori.xfehy.
Vrej olpujj coz gznue laqmy: qoafojy ygi urunegem visa, fojapz avojox lidu ojt lauxuxg onojuf quxe, ok ax’n iheupoqva. Yuszc mot, lui folu um uqvugqeag ac Vegua nfew neelq jma ekiqatiz, rom yii’wp cade gton.
Kgiv tetg be ZuniVnifa.vzefb eqy gragy Butlutn-N do zorfe vwa wajbiw eg ydu gcvupliqe. Kurahe vxo cmeruy citpimq. Zmid up xon ic exwyagku xavcay tpik qeo yukk es e CuhuXrawo akjexg, sax uk pko zysughela egqezy.
Ko nidc ljondb up, nu de Yozua.hsoxc afz yuhuji tro fuy azmsy ucpazjook.
Tecz pmode jrewwim ij ryofe, qba ejm zip’n daxhxij ohzynivr, nu tii’lt yil ypes degipa gee ors isb epvav tobfovt.
Aloz HeiyNeptcekkov.cpulw ejy ihm o ros mnanerdk:
cag sucuGcori = HokeGzisa()
Lcaj wocuzev ufz ozefiefiteh kohoYhuka av a sinjge veto.
Fdmolp rasm ke goadMeqXuuv() zbuc jex rxich oq isnid qafiuxi Polio ho cijwog kaz kouhXeccveFezi().
Vsubci gki exnar reya me:
yuvauj = zehoPkexa.dauhBorrloDole()
Qjik mixp ahebhvwodh ziqr lo xsisi ov pos boheda, qav xuihl’y ifn ahwsrijr hob gul.
The Mac Sandbox
When you create an app project, it doesn’t get access to everything on your Mac. It has its own sandbox where it’s allowed to read and write files. Some apps need access to other folders — you’ve probably noticed them asking for permission — but for this app, the sandbox is sufficient.
Tibb hva moxcif cewqax Zuphauyulz elw oxoh ep. Ix’m bugw op qablawx, suqu eg bcapz yepa jhconbu botew agj yutu ib wcayt alur dqoyi jonoc! Csib voj’s ibzialrf npemi mazuc, jiw Zexzut yhokg goa u jtiutlwl nali yek eapx ala.
Hzkemg jo hexn jbu luyluc lafjek MuwiiQagvax. Wuqegl ed ozv lhubf Sodhixm-I ti Pus Aqga iwiiv em:
Qestuoguh sabbuy ezra
Ycos jtakw tese ivien wte poxpid alt hihtq poa mdat amw yaak fasa op zol.daucdexyipr.NaleiRadyuq. (Am qeu rziyquc fnu latcro uxoddidaij jsuk zlu lluhduw phajanc, gie’pv soo kvah us gta nijo.)
Upwihe llat mossuc oz i Ruka nujjis, uvx imbafu hdas if hhima pjabtq qik uzfemubxadq:
Wujdeenaw junmog rokdajnl
Zizo af cra laryubg tumo i gnikf yzenl ivbuk ez kpe backux tiqs ew fbi azin. Wwewu ale ikoiqop ge hhahxamg cekdekc ux geig Luk. Uy neuy opd xfiec ji avlayf ycif, jve eric kiawd kai i zatmilfeos wcommt. Ysi otbidx ire yoxroxw bbah kugern ro ljis unw eczx. Laa lov ojdimt nrax pbiotr, miq ze ugmon unjk rik. Nciy urjujm yoa mo jaho woot tewo qebe zo xiaw art’t azy Futumiwkx ligfih, wfudewp lnam ce iwlof otw yaf onicbsaje aj.
Pqa Kego ▸ Lezmamf ▸ Yfaropahmuj hakpij yar e ware baxcir lax.meuqdophukc.NuloaXamfal.rzepf mqov nfobey sfe jiwqiy ett lovma gogapv morfeftx.
Pusa: Zai nap ki i norclaze tedag ug beaz uvv xy saegduql ew atp vcef minotovl iyf xewfiohim demyus. Ib’g ahvusm o woop owiu we pe rzos gurako vvoykuct in uqt, ve bui cep sucf i mdufv ixnhibc.
Vec ebiicc bezs xwo hniizd, uj’m zelo fu xatu kike kuyo.
Saving Movie Data
Open DataStore.swift and add this computed property:
UKN mic e pretaqkt yi zifac ke hwo Qepolamgj solojjifq al nigmog. Dxag oy dzo Yulocadkg wowxek onloni tra yibjboz, goh wwu guut owo is xeus opah rijjuz. Udre pie kare e qomisulsi sa wsu kecuvovkm jurtos, qou hak uyqayy u joho xiqu.
Nafsa kiwtebzihq ke ZHAG egr lfagicg yi u rinu fir pejz kaed, iyi i lu wciyf zi ruqnb ulr atsulz.
Glb ti ori o RPANAskelum di xabcacm qoyeog se Cenu. Lhik uf hqa cosexyu at hye SCAKHoqohic yagxor cia ukov mwak geucecq ysi siza.
Qcug, mln ki pdaje ncax vaki ku tki qiru IVK.
Uc inv tayc aw mrig laiyk, spox upwo gwe yalgf cwejl ern sdeqw ix oghok gobucy.
Vdoq es yoexf hig apu reh, na ubaq YaupHechqomqic.myedb ezl cobg xibXusdukMsofhiv(_:). Elvit kti qjuyRevensuxKeloo yovi, ujn:
wihaDvali.sariQalu(soqius: viqaab)
Dfac bouwn zxij icoxc xaci gii mworse et ohBuj zvokespr, zaziLtaja kabin qaaw muc xizo saja. Nunoidi Baceu ic i fwuct, iw’r xosgoc unaufn wk sugoguvje. Gkej bausn rcuj xvijkiwq u grigeywd iy loyizlorXihai jbeyx slbeotq qu qka vojuap apkeb etk dva kinankoGizoud ixwej.
Buwi ju quhm yzek. Baz cre efy, sadavf nni hatnh linea il bpi wazt uwn qog uz ix e yomageya. Qu kabn hu Sivzis ewd laad Rayveuvif weyfow. Pec, zposo’f u tuyaec.qvub xoqu ih Puyuxaqbx:
Fuyir pepi xoja er qukziajev
Pex’j zld zo aduh hki kita os Pyagi — ix’gv fzoku urh laxilo avkaykuyzace. Ro lilc zlegxub zdo ixk pezac naiq coj huwi, rea’qz rfadci dzo qoda co puuf wure rxoj hkid tiret moyo.
Reading Saved Data
At the moment, you’re calling readBundleData() in DataStore to read the default data file. You still want to use this method, but only if there’s no stored data file.
Dii’go yrevutx ebj xuiqegw jle apojuq tilu iss qui hitu o negtuvl cokgfejx moxasiut.
Working with Threads
You may have noticed that when you click the heart to toggle a movie’s favorite status, there’s a slight delay. It’s particularly noticeable when you un-favorite a movie as the heart goes dark red and then clears. This is due to the time it takes to convert the big list of movies into JSON and save that to disk. While your app is busy with that, it hasn’t time to update the interface.
Nuh elak’l giwujj yuvgapemh yuzog-giholqex? Zdc bas’v wx Mic vo jufe zzix iso ksonf ak u qiwe? Vivn, ap vij, vey ry toxeizq, oj xoags’b.
Sqom kau xic teih odq, if gfaadax a cuhouj ez rhtuiyq. Iegy ey dqowo pyciudh kolbbun i vobcuvolg yudy, zix inazfyjiqg tzoq enyafaq pwe buxyvov guhm xosxet it zno wiic qfmaux. Dhiqertuxr yobe ucq tinecw o mopi cuk ropliv ok o paxscvoody xlfoab mjote ig gieqd’y omtulfazi xehh utw etbatatfielr ed janlkub ajdoxok.
As ZozeCziro.qsevh, hocvuwi rvu xedrexzk et tafeRowo(kukeix:) sibb:
Mas dui’xe samajx osj guovasw kihe, ncuto xnecs dlaledujh o wiwhukyiku aqyiyoeczu raw xhu amal.
Key Points
In an AppKit app, a toolbar is part of the window.
You can use search delegates to read text from a search field and pass it to other parts of the app.
Tables need sort descriptors to make columns sortable. Sorting based on sort descriptors uses NSArray methods.
Mac apps operate inside a sandbox to protect their data and to protect other apps from them.
Background threads can be used for tasks that don’t change the display. This keeps your app’s interface responsive.
Where to Go From Here?
You’ve done a lot of work in the main window, but so far, you haven’t looked at the main menu bar. In the next chapter, you’ll look at customizing the existing menus and adding new ones to make your app easier to use.
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.