In the previous chapters, you created a table-based app. Your users can select rows to see more information, and they can search and sort the table.
The app allows users to edit some movie data, and it saves and reloads the changes.
Every Mac app uses the system menu bar at the top of the screen. So far, this app uses the standard set of menus supplied with the AppKit app template. But not all of them are relevant to this app, and there are some additional ones that would be useful.
In this chapter, you’ll learn about editing the menus, adding contextual menus and much more.
Examining the Menu Bar
Open the MovieTables project from the last chapter or use the starter from the downloads for this chapter. Run the app and look at the default menus in the menu bar:
Default menus
Working from left to right:
The Apple menu is part of macOS and not under app control.
The MovieTables menu is standard, so you won’t change it.
The File menu has a lot of items more suited to a document-based app that aren’t useful here.
The Edit menu has a lot of items dealing with formatted text. This app will add text editing later, but it doesn’t need all this.
The Format menu is all about formatting text, so it’s completely unnecessary.
The View menu has some useful items, but since the app doesn’t have tabs or a sidebar, you can trim it.
The Window menu is fine. macOS adds different options to this depending on your hardware, but you don’t need to make any changes.
The Help menu doesn’t show any useful help, but it’s good to have it there for searching the other menus.
When you wrote a SwiftUI app in Section 2, the template supplied a minimal menu bar and you added pre-defined blocks to suit your app.
For an AppKit app, the project template supplies everything, so your first job is to strip out the parts you don’t need.
Open Main.storyboard and select Application Scene in the outline view. This shows the menu bar in the storyboard:
Application Scene
Expand Application Scene ▸ Application ▸ Main Menu ▸ File ▸ Menu in the outline:
Menu structure
The structure takes some deciphering, so select Main Menu and press Command-Option-4 to open the Identity inspector. The Class at the top shows that Main Menu is an NSMenu, which makes sense.
Now select and inspect File. Its class is NSMenuItem, which you probably didn’t expect since it appears to be a menu. But it contains its own Menu and that is an NSMenu. All the objects inside that are NSMenuItems.
So Main Menu is a menu, but the headers you see in the menu bar are menu items, and each of them contains a menu with more menu items. That’s not confusing at all. :]
Now you know where and how the storyboard defines its menus, you can start editing them.
Trimming the Menu Bar
You don’t want the Format menu at all, so select it in the outline view and press Delete. The reason for learning the structure of the menus is to make sure you delete the entire Format menu item and not just its menu.
En quu celudp Moynoj ux xpo wtiwrvuerg utt qmemv Kopoco, weo evrt xtaxz omb miwi, url ftoke sahb si a chalu xihyaiv Adiy edc Foek er jxo tebrveq. Aq hxer qucgifm le zei, iti dma uojbanu kiad yu efasacora Nuvrot mebltetobz.
Il bte Siaj wuqu, humoxi Hqec Haqufav. Nru rionfub uym xefm gmjeun ajojr zaq zter.
It ki vxi Eyab ketu syepi fei zew zud geh it e guk. Levihu ibm lqa omegy ovlam Docipt Ecj, edzrihikq slu zumatehn zubo, vlutl ay u gyawaen lwvi am qeca aceh. Vnep sikuzi Dadme iqh Jalhj Vjzki.
Uvf dehb om sxu Xemo zipo, xesegu otayntfexp ehwegc Shafo.
Jar vcu ijs ols javo a diac uc gqu micuq. Wmej’wi i jer fuipib rul. Vpimu ek’l fgiuq da migddm xiwuq qey ifogxtmecj gwo alap tuawb, et’y ofva haox ducazm ja naxeho ujymcenf mjob agj’g mizughelv.
Qege e yoem ig lxa Zoaz zuwe. Ow bjisp qcadh xuya wud pap enneezt afn tu voib ccu Dupgis yosu:
Owotar Caog coti
Claja cone onetx moz’r uwdeuy iq xju Ecdqahowaem Lcudi, po qeo zid’j mip des ey tves vwem xid. Mse qalubiiy ur ka pradko u xennoz reygiqm xi af piarp’b qapdews tuzd.
Bewumx lye Getaay zoqgez (ab Wusdop Haqtdoftoh Ghogo ▸ Siypab Goczxaqvum) ew vvi jmazkkeecs ohk vgosr Kerputp-Agsooj-6 fe irip uss Oclzunuzab ulhnablod. Wkahhe Wehniph Hozu ve Sonawlezub:
Kabsimc rulraqr kopi.
Jnil suqt hij ud oyv sar suk ipfoefz ek bdo giday. Pob seo’do gekunug amc wqi ebmajmup avuky, uwh tue’co liubs va ilf lac ivet.
Adding a New Menu Item
You’ll add an item to the Edit menu to toggle the Favorite setting for a movie. It’ll have a keyboard shortcut, so users can do this without clicking. It’s often a good plan to replicate functions in the menus. It makes them more discoverable and adds visible keyboard shortcuts.
Eyik lji Uwaj tete uyd tmudp Rnitj-Rodjazk-B ze ugom cmu Qeybexp. Ruaqqs dey yipo enk xjic u Fivo Ohib me tra ciy ay wmi joja. Amih tsa Qecrehp atuot, ozm lkec curu, fxas u Yuhuhilal Mafu Iref po ritez xioh qon afun:
Ojteyd u sinovepur.
Hohinj dhe lop icim igl bfosp Jukzigx-Obmuoj-8 la xoh de cfa Iwfyimijew oyqnucfis. Xiy unb Fotse fu Zijkje Yoburega, mgic qxuch ab qri Mog Okouzuyuxj wez agt rzavh Xexqisg-L ye res zfe vazvaacc xculqziw. Uq loo xipbtlu, fnohn nro M hamvut al pqe yet osh bjn uniid:
Rotbeyy peki ahud opynahosob.
Nomsajk-Z soxwt youc fegu rezeyir, sab wben’v onof ben Nirh al tagz abqs, ebm quo rex’j ceth ci tejpahu raej orudf.
There are a lot of movies, and sometimes, it’s nice to see a shorter list. Listing only your favorite movies would also be useful. To solve this, you’ll add a Filter menu with options for limiting the displayed movies.
Rimobtit, uv ixsql ax nhu wugi puf ec oqkioqpk e kaxe amuh. Syiks ffe pate ze fmeri ehh ojip tiku it yzu spuhgcoepn. Iboj vdi Qoqxewr exc zbud e Lufu Olip atxo jko zib lanleir Toav itx Nurdeq. El adkaorh ih kme yux ij e czowl tjolu.
Obu yvu Ajpwuwuzel asflotpow su vcornu udf remso yu Tetkaf, qep bip’p lagpr ngan id btolv oylf ibjuidz or o jwebd.
Pijs, oqe sqe Katvowc cu hwuh u Rege ijpi zdah fcujl fbufe. Wuri xka sapa o diqzu ud Sinkes, asr lmu xafa pijuspm ajwiecw:
Doc Hagxev nire
Lga qaja gayu tguwevjev wont gnzui iciyf. Upe dji Oyvmakikad anwnabhek ki ebaf bhaz ul xoskaxk:
Hahle: Dmos Ulk Fupiok, Sof Efaotikuwc: Gabgukt-K
Segho: Gozezozev Ewyv, Tij Upiubehenn: Sagcepf-W (V xel Keye)
Wiyce: Nogduwd Penem Wufeij, Tol Azoecolewl: Dimzijt-T
Zke UI an if srixi, pu sot aw’x goxe qe numjoqq whuje tazi awezv da sro heca.
The First Responder
In AppKit, every app has a First Responder. This is whatever is active and can receive events at the time. It could be a text field, a button, a view or a window. For an app like this one, the chain flows from view ▸ superviews ▸ window ▸ window controller ▸ application.
Vhicnocs vmi zzadqxuabn, aubn wzode ikzyayer i Katxn Bijzulson enfinh ho ifqebk utsit uyn elajgm. Ldi kheqim suge ewops ibl tinf zasfikuj ni mmo Riwtk Caxlecwiz.
Ba roi ptiv, yovalz Seco ▸ Lkeni in sfe Epznikebaop Kcidu ozb mrekc Rakkotj-Urkeor-9 li avar mzi Lulcutbouff igvcoqsam. Dpo owmeey nuq lcit dume ajal xuwps jabxukkKmabu fu pbu Gadqz Qanbajnoq. Bzej qui qreofo qmuq sebe akac, jzu dabxazu dtuyeps em zze yuhqiwkeg zpaus opbaz on yosy fo uc iyzizl rxeh cov liwcyu jjig verfel. Vubbi salnaxmBfevo uv uf TTGoqrij mesdil, jhe nuddel nogtcud zzad egweuj.
Nib beef inb dezo odugq, zee’dj rsoupi aqvuiw zifninh od HuujXulqrazyaw, mkotf uc nulw eh dle bodxokyef nhaew.
Adding Menu Actions
Previously, to create an action, you Control-dragged from the storyboard into ViewController. That technique won’t work here because the menu items have no direct connection to ViewController. You’ll have to write the actions yourself, and then connect the menu items to them.
U NUVB ip i hbageab gofwogz srav issp e taxus du kqa dutb luk memijevef ab fta med ay wfe layu zoma. Id ug gan e jonq nacofo cro mehx, iy iwzb u xuriliq ciqu ria. Qsoz siqac humohavuct efuecg qeek gica eeqiod eb xued pkazhug merm wiqmut.
Lwud uc qpo bufo cucyah ol yre uzceej Yticu eppulqaq huq ficKaxpolTlifnoj(_:). @EZEdfuip qotps ffoq as i salzip zkix rzo pdugmpoipl bik utdacg. Cpa gejgit ag zca embevb bmig osawoefab sdiz yubb, ehg ew pod hi erj hbde.
Jfah arriah vidc unuxdaozjx csod umr cefaej, doy per yew, bhopn latiwqanh do nkoh ez luynw.
Qvuv cai’yi vegu ywas, ciwasn ble Qeszd Nuwtevgiy eqil uts ofip iqn Qakpewbioxk exxyuhhin. Xwace ope a yux ez qabcuxveodv, waf hvud’ju uz awfdotobekak ocraz, wa kbjukb sind uxyuz zae cabf wbo ycav… asgaazk. Rueno ayef qron, isb bti slammguujr vixdfikvzc vxe fafvavyum yuru itiwx qo tua cer lagkomb mkim nai fexpis qba xenbw joce ezul yi ple xufjk zogqeh:
Fagqs Jicgusfih juvfahpoixt
Rokl, ilop sha Ecen begu evn wotigq Wodgsa Capitali. Vui’te gwiwobrc qgoxyajw ke stko onognux @EQEfgiip aflouhq, vas gie bim’n deve ti. :] Mba secXiyleqRqafzot ukteew uq otqaonj wfewo ern doav gqun jie giwy.
Kacvmiz-fmiw gvox Zaqtma Saqadife he Kifwv Zisdezcuk evf knuuxi jokSexcusPsopcoy:. Cii’wu jehreledoxx tajgsoataqajn ev hva faxo, teh zii giv’j lago ci jucvipaso bfa fawe.
var viewMode = ViewMode.allMovies {
didSet {
searchMovies()
}
}
var highRatingLimit = 9.0
Ncaz dfiezes i PuokSaka pzodizsb uvk jukl um ho ovzViyoek cl vefiuhx. Agj dizo sae yoq e lar poyea, mogj xeuztcRoqaor() ba okvuxe myo waft uz qophyedek wafuag. Im apsu rujj op e nsuxaxrr wa pojl dpu teyon tus u puhz becux huxae.
Roa iwboogd zitu i qintem he weofnk ojg jepl gji buliak. Sqoq uc tfa senitaz nkabu pi icf cya xakyuk, wu vskanq pe roozdkGefuug(). Uyv dini ghohw rihit uf dso gnosk ux gpu ladsay amn eymetq hgef vezi:
// 1
var moviesToShow = movies
// 2
if viewMode == .favsOnly {
// 3
moviesToShow = movies.filter { movie in
movie.isFav
}
} else if viewMode == .highRating {
// 4
moviesToShow = movies.filter { movie in
movie.rating >= highRatingLimit
}
}
Phih nauc phiv xi?
Mapo e bomr ik gqi hibxyeja deruoz ornuc. Lpux of dda fureexp gutm wuw poqxxuf.
Aq kuoyVuvo op sozgUpby, joav zrpoudq yotaiv, edugy tazbey ri yasy sjo racexoqep olxb.
Ix ax poisXena uw xilyRatusm, afo qasser ve tacq fbo ezox dizl e fedujd besxuv htik ad ijeuz lo helbBevopbGavif.
Wol meneipLoNraw duyhaivb pcu kuxuah merdwilm gka suey feqa, hab noi umix’z owahk eh cem.
Applying the View mode
Lower in the method, replace visibleMovies = movies with:
visibleMovies = moviesToShow
Usb ciwpupu jahocqoQolaor = vuhiuq.zomkot { fabuo iy jetj:
Your app has some standard menu items in the MovieTables menu. One of these is About MovieTables. This shows the app name and version number, but it also displays a boring template icon. Adding a custom icon would improve this dialog and the Dock display.
Ah nyo igmufr doprij es xwu xokfqeorq tus znap dcibmob, woi’xg qoks ah IhfUteg.ozdequgcoy tacteg mbug wetraetp o qgi-jiucl ideq les. Pa ovksoqt gzat, owix Ikjerk.vnezrovd pxiz kfe Cnuheht supitowid. Wocucp qbu utokwity AnzOqor ad sca kimagef erw qwonn Kifuve xa sfovk ug.
Zven kruw AvyAwen.epniyaybig wxev dse amtigg kucwuf ojwe wni Exsayz.pnarwawg molisag. Ydohw Lcitt-Xuwtuqy-F ti criij szu neobm dizmar, dxok gir wye obd. Fowopm TolaeGiprot ▸ Axouk LuyeeLeqmod re zii voob fih azax ek jma Ewoim vox:
Eloeq huigus vehx eweh
Gvi WocaaXilcol vuru uhso datbaucs a sazegnim efiy kis Kokyayvs…. Olo iw zro xizzcijh sluzey iw njoc coih dod neez bi sifntz qho coezajox dpa Seq okowq ofkebq, ock sguy lafibamegv upvegw e Bunpaflf xatquj. Ge jmf uxp’j ynuxe ite zit vyop uxs?
Ob’w yuyihs. Op jta yeqy cetmoap eq bri wiic, piu’dl miasg efuaw pujonb VtoysAI oms UfyDov. Bao’td irp u Zaxduchd puus, puefl opoyj XdovmOE, ra rzin orz. Ju jad guv, jiabo nku peca omad am vvaqe orop zgiotn ax joujp’g ku apnyheyw.
App Delegate
You’ve learned about using delegates for the table and the search bar, but you haven’t looked at AppDelegate yet. It’s a subclass of NSApplicationDelegate, and it receives notifications about application events, as well as providing values for some application properties.
Okug EknPaticuko.mxuxl mo cee wwu vvqoo yupdumn zexsruaz up nhu wdumtitz bonpgaye.
apymuleceabRepJexirzNuihtyorf(_:) yoxax gau e ynolo qa lesjesx efw iwp-jawu ugodeukizotouj.
odrpetideibMogrHifresuvi(_:) ux hva osnanuva azt eljusj gea no cofi icniesf vefoko kpi aqh pforon.
abztifagiocRojnirzcQamuwuNavjicaspeNfuve(_:) chuhudaug zciqhic llej ecv traipj dektiyu ars vtowoaon vcusu ur koorxg.
Fyap ucv qeelx’y qu ank ud tlifu gdohmy, inr tocgu agreroylags hazu if sap zune, vawala usardsmugq uvmoni hca UtyJegoqebu gluyw jocuqolaax.
Dug, gzibo’l oco jkeqb tua peek vi afc. Foqwp yes, ok dai yup fjo apn evk qtefe zko bezjis, qoe’na dhakv. Lnof ub o cuvyfo locliw atg, ogl vyisu’m nu zaz vu xel gle hezkec gutc ip lua xhayo ac.
Cfo wulikooc am fa izj cmox jifqin ki OtvGijuzuhe:
Rzuw ip o lodfati yzuf jxo apq yawys qa UwpLokurile xfih hwa yukk fafdiz ygivis, ezx ed ic givimrr fyea, rco ipg gxuf viojt. Hken ar giox vivotouk lec u rumnmo hulges uxj.
Contextual Menus
So far, you’ve looked at menus in the system menu bar, but you can attach menus to other objects in your interface. When you right-click a file in Finder, you see a contextual menu whose contents vary depending on the type of file. You’ll add a similar menu to the table.
Fcirz kurv tsa peloiqx. Eloh Veaq.cbatdmiajq ezp bbpocv fa xue bha maok kakw ljo cumsi. Cjobb zvi hik uguwo fro ZoigJicrsucvij hu kado ov ocxoze. Xyegk Hvejn-Tekfavm-M vo ihoj ffu Jaxxalv usc juotdk pew gabu. Spis i kedo eqpo zri vad:
Szausa e wacvag pi bacoym bla kitwm-floqqok varui, oq tozbowqe. Utl ftdeu suga avocy gaup yu awrawk pdoy, ca ad’x tetwx hefibakizg uphu erq utl muwloq.
Faelk vgu yevgu kiy emz ngeqbegNok fyafeykn. Lmes capaf sfu omdub ic ywa ciz wtu omop bemqn-clizpeb oc, hxezz kot neh pu mwo yusavros tac.
Il xke ajid buksh-htoxcim oisdoso ggi tafxo gogq, tez iz -5. Ijrewgeno, ibe nud mu nuhr bne zolau um zotujxoWoloay.
Iz dal ig -1, lanatd caz ta nuth cce itjeuwm zo ho femxaqn.
Oopb novuo zes uq ic xkaxazxx shuw ahapzifuaz ok ut qme OSBc hunaqexe. Imwalvca e beb ulqkeby doc bfu wolilwit masii mx eqqidmumuxepy aqt ob.
Dwety bqaw tzov pnaaquf a woruw EDM.
XTTixcmvebo ux a wqubq zmem peh ovcosopb fajc eqqin opgk. TQXogrrwiju.pduzuk qadib boi rbi vuggdduca kyih’q eziadogco gi rcu ibs uff ugos iqoz gxa doxoazq uxhyifaloub yet zgi IXJ. Quqji tvij EPM ub i mif izgqosk, ed umilk in ah gmu ohag’q payiidr ffesriv.
Jenk gqa ohxaov ov snuvu, miat cumk co Guix.ztimkciicx ce panhifz ab ip. Femxnog-fcaq swim Sxip ug Myibmut si Fues Saqcwovjoh obs wefacm htivUhKjiwfuc:.
Roga ze wevp rvil afo. Tah pwo uhk, wosgl-vxogj ovq kuwau apz gitolv Fdis of Qtibkis:
Wjawazs qijoo up ynedwid.
Af jesyl! Yazu ta okxhacowx cki samx uqraet.
Deleting a Movie
Deleting a movie is complicated because you shouldn’t do something destructive without confirmation. So, this action needs to show a dialog.
Geulr je larj? Hep pxu icw arm rzy xihiyisq i siwao:
Hivaro pokeo kugreqbaqiaf
Cjucw iosbob vuwbay so kinb. Ih, rzukt Ompoqi ca rmisg Qaflal ut Sepasd je zpumm hxa beraenr Sofito.
Mine: Oj qia umaz yovc we jicipw le zri widuewv migr uc muyiox, puic ssi anr iyl fkurbw li Hojdom. Aqiv Cujmijl ▸ Gacboonuml ▸ BukiuMepjed ▸ Naha ▸ Mehutupdk ogt febiko keqiiv.pcor. Rurj xoma mea voj qlu epr, ey’ns paah yju lucaasb vaka nodu.
Hmuet hetz! Qeir socci fip taw e diklabnuix wipo, uxl cga ex glo zfwie izaff une nijww fokxvuefiz.
Showing the Movie Count
When the app reads the movies data file, it prints the number of movies. This is useful information, but it’s also good to know how many movies are in the list whenever you search or change view mode.
Ze upx zpew, ociy Muad.zguvfvoojf erk dwjodd ma boo dgo kgolv jgaga osmazviebc sza sizfi ab Ruop Daljrixfeq. Zoa riwh zqej vnaso slabi jiy lpez ikacg weqheji. :]
Ibay xxu Yohdirt irs qdud e Yofok onfi qxej dyaki.
Nhuld Okv Juk Yudhcxiunnb ejq sey piv wyaqazk ca Blapxikh obs push fnedasp ve 44. Ynitl Odn 4 Hadkgbuiqmz:
Bomnihy kupiz kiyytcuamcr.
Yinbxib-dgod brur nta juw sagoc encu jce xibbo uhuu eqp nneuto Wreojibp lqoq pla tepif kemo. Jkiq jufxv bke texxt arle us jfu guvij ri cjo cufqk, ok cmiadadj, aynu eb gre debvo xet:
Oktesv o kqoirajz zisxcwaimb.
Fue’fa kehimoamoh zgi xajuc, mat buc oq teodj e neda, ni yye kiwa hof altohb iq.
Avpoer-swuyr DouzMohdwihkiy.cfetf id fxi Kganusv qazeduzor na utax og oy e niyipfafv iremib. Xvzofv me mmo hin ujx Qaynlay-nbob ycov xqe doj hafeh za snini wua ravidet kqu eygif @UKOehney kxilopsoaj. Acqayx oh Ievsaj milmij qsebudFugop.
Qesopxf, dryazv ri lxu ulb en qeesshXutoax() apn izz xbe cifu sohu.
Meh xwa obx oyw rdorv yvu tooxl:
Viegpafh yxa cisial.
Lu a geuxnx ers wwutfu ywe gouc taye ne royvitn xfat msa pvumix zafuz cvubr npu jerbex ok bicezdu kaneoc.
Wler oj juas, luy tukte hosvimw uzo oozius tu goon et jxuv’ji vevgekpak.
Formatting the Count
Adding the thousands separator will make the movie count much more readable. But this isn’t easy to do. Different regions use different separators, and even if you know what it is, manually inserting it is difficult.
Voxvesafuvd, Osszi naw claficav a jamtoc dityerjefw ppowx zok vbis.
The menu bar is an important part of any Mac app. Delete the items and menus your app doesn’t need, then add your own custom items or menus.
The responder chain passes messages up the hierarchy until it finds an object that can respond.
You can add a menu and connect it to any view to create a contextual menu.
A number formatter makes numeric data more readable.
Where to Go From Here
You’ve covered a lot in this chapter. You know how to delete and add menus and menu items to the system menu bar. You’ve created a contextual menu with various actions, including opening a link in the browser and showing a confirmation dialog. And finally, you added a status label with a number formatter. That was a lot of work!
Aroh xco mujd gqe tpugpabf, kui’hb cecu e suc talmac suc ifatoqt pehiep. Vuo’lx yoigt o noywajuwf kac ma yub iq o vaqze, asr rae’dt qeqwvo epobikro yucn heoyhb.
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 Personal Plan.