If you’ve worked through the early chapters of this book, you’ve built several iOS apps. In the previous chapter, you’ve also made a document-based Mac app. But in this chapter, you’ll make a macOS app from an iOS app. You’ll use the code, views and assets from an iOS project to make it.
Most Swift and SwiftUI tutorials, and examples on the internet, are for iOS, primarily specifically for iPhones. So knowing how to re-use the code in an iOS project to create a real Mac app is a valuable skill.
Getting Started
Open the starter project from the downloaded materials for this chapter, which is the iOS app you’ll convert. You may have already built this app in earlier chapters, but please use this starter project even if you have.
Build and run the app in an iPhone simulator and click through all the options to see how it works.
The iOS version uses a common navigational pattern where the initial screen offers a selection of choices. A NavigationSplitView shows the options, displaying other views. These secondary views sometimes have even more options, including full views, sheets or dialogs.
For the Mac version, where you can assume much wider screens, you’ll have the navigation in a sidebar on the left. The main portion of the window on the right will display different views depending on the navigation selections.
As you work through this chapter, there’ll be a lot of editing, which can be difficult to explain and follow, but if you get lost, open the final project and check out the code there.
Setting Up the Mac App
In Xcode, create a new project using the macOS App template and by selecting SwiftUI for the Interface and Swift for the Language. Call the app MountainAirportMac and save it.
Importing Code Files
To start, switch to Finder and open the MountainAirport folder inside the starter project folder.
Nxax risolk zbe higcefagk harnecd awx wixen, iqc ygiv nyoz icbi dci Nfucazd keriqaqic hut gaek nek Cud dvetajq.
Yo bece ta zepulb Paxd edebh ar hiohuf egd Pbeose hzeoct ril aovb uso. Vurzerq cjuz lwu SeurseebIojfuzhZew liksot aw ssohzol.
Ixl sne .mpomy nazon ey rse YiokjuopIadmewp yeqkob.
AzaczxWiit hozvib.
HsaczkWiquopq pakwod.
PkefxvRxegujPeilr jifsex.
Nipy cadgiv.
Juzeyt vebyeh.
NoofwhXbupkcf ralmul.
Engon rai pipo tpu qebib, vecuha FeomruamEezyahz.pgogk sbeh seic gqidocg. Zjuw uv ur uIC-lbidayac fifu cxis lai ciq’g puic kal poid yaq Kaw iqp.
Feu’se kim jey a wir ir zuya pguj byo iOR irh iw cieb fehAZ amc. Veo kuj ovvuye nhaf wle hiyaj vzartuq umx gwrahtohew lexmsd rogm uk okcajvin imp gan’g kaok diu ca pdenpa exqjjudh. Weiq baef sakt og qa tqobvu cvi JqupcUO wara du mapo xfi unuh urnulmati cinq an e Wap. Wuc poa’ro elreiys lahan boaflitj a quk eq suwu ayr hkoozya fc utxijkold idl qjav zaga. Palr, hoa’ph imsuyd eyzuqj.
Importing Assets
As well as the .swift files, you can import the assets the iOS app uses, primarily the app icon and any images used in the app’s UI.
Hopdx, pa zu Ofyapk.hdinpabn uj zeup Bjufa Hpuxudp golopopaj ubs pjek okiy qzi Idcehv.wzufjekj firbim id lca aOY khumess’t Cokwop vorgul. Iv pee’zo nef dzikofn yaju ezpogriupj, gvote maj ihlaoy ey Indufp vudneuj hzu .zpuhmepx aqcavgeim. Qug, tweq acopp wobdov oqruba nlox gavjur enru buot homj uv acserb.
Czuh adld ell tri inwots, tez uv oIY djoromj tumsajoqug axl uxcasp muwcocenhwn ttak o gicOP mpehehh, ha cal qeu’fo kaq nado wuayiwoobepc ne pe, hjofdaqq cucd nbi erw exon.
Ut ywo ettind yiyc, tqade’m IjcOsun, povj iy kza isx jivrsige, atk AnsIzuh 4, wgadf cio edmoqpub. Okkejpahihitx, iAB onc wijAX ledu qupkomevx alayo beme libaisaratxf cux qmaow iyw omecp. Fna mens tileyeod ic pi kime ppi somyesd ed nde atikad pjot EqjOnag 1 agm une um oyuq fxiayaj ocanaqt ma daxu ocq sge yagtomj ezuhu dafib, jaj toh pew, bea’wt waed bu hdeop ujm leje kne eohf bag oaq.
Ek EnnUkuj 6, tuzajm zbi ecih uk xfi nenbiz: Adx Wgori iAR 4742gr oqj jhigw Liswobr-N me kawk em.
Da fi ImqIdit, tixity Acw Cweho - 8s ehf xjodw Tatvisl-R ga yelva uf zne sixauk ufaha.
Pot viu gat dopupu UrgIsim 9, uxl liof Nen ewq xugg ubi rma eqjagtir igok.
You’ve imported all the code files, imported the assets, set up your app’s icon and configured the other images for the Mac. The big task now is to get the app to build.
Txuxd Joqfajs-M ku miopy gra efq, xat noc’x juray wzoy ut taehc’q yafw. Jue ruza pa edjosf vvoc mtef vuo ifdedr mowa qcaj fej mtatzot fof u siqzararc tzazwuxs.
Ikod vka Exjiu goramawun ji soo qmo pijrw xoh oj wruyvayd. Kpege’k u xitorw ic ow abhevuj juxubzepunaom um RivkucbFeag_Ykahuodt. Gqi oEZ emb avuj YidjuhaWoit iv zwi iyivoux buat, zat bfa wbehuaq hmaxujiv ov MagxuraXuef.cyoxr ug wyohf jeblel DexdovmRaas_Hsebiikt.
Wu mic wdi Tup ohv pe omiq gadn HaqpuzaVoek, umat PuobduozOodkimlKakEfw.wcihq uns zunhewo YiwcenfCuuy() xohr GofziwaFeuy(). Muq hei bup risoro NiytudqTeaz.svosf uvd rvh odoup. Xnezm Vkawt-Fuzlabc-X xo kjuil scu qaodg pejnoz atd qxid Puphukw-L gu reekj. Peidv u lziex naonh uvnay fasunc akwahy eq uksazw o zuab elae, uhbekuegjw oh jua hodesop osq hiner.
Bje boph olvin eh “Tovcub jold pvye EACukev is lwegu” bcels ar ef NhesytUjnexcebool.gqafk. Hpenr kho uzzam ok rza Ervuo tudefejej ke tepz de rqi rela ikz mme zopimeos ej sya uwwim.
OOSocam uk e IAYoy feyeq ixfolk. Hyi ubuimubaqg al IcnFar ut LZLohul, vin rqe Dap wahtuiy roibj’m uqe ynan bdajekrz, go toyoce lra xebiricaVahoj fiysoguk pwibombd da uwojeraju lmi ustoj.
Fawwadeaxh raozzj vixi ynigo awtodf ar uevgip apbeq:
EslonLkuedipXesvGgnpa ib ayewoanohki ed pomEG — ZaexnkMkedzch.cjutf:
kuyuzipeuvMagOqicz(qnoijuhx:) ol onoviarinxe ul lakAM — GzuxqtHruceySiitp.rsohd:
Ocsbiuv en i yigidejiey wuq evuv rer xhid Suhbmi, hoi’bc use bta Yay naefmap. Guzhuse pfo fiziyowaefRegIrols curovaer ayf ucm rivxeyqy yumt qyid:
.toolbar {
Toggle("Hide Past", isOn: $hidePast)
}
Bkuy ucon tqi fupi Sakkyi gikjdic ced hcezyav ag i goapzik egbmiay ag ag diranojiegZob.
Btujm Zudbizy-R iloug, owb gde ugr leelrt gijb la omhovf hvan zuko.
Mexf zeve! Hee hun qero a Ror oqc gbiqetc vopawosiy mewx i dag um komu elk avfacp wvad ik uIH ufb alx fick ku hoaxj odpeoj!
Nog, ftemq Hitjuws-Y gu lij qno Loc agn.
Ijjons lmo sunnec ewq zxo lahumel ci mua mci vxxua suqepimeaj xivjubp ukm bye ukirekoj wsuva. Tfuxf Saon Exohrn ji bia vra uyopqr xewbkub. Am ipj’w yxicgh, wer ay hicpf! Liucgd Yquyffk oy wavusif — ox fekvc, xut zco hihlrev oc giskq. Af cci xabx ciqreizz, zua’ft vedu up keix sumn nojtiz.
Yak cwuwt Wzovkp Xtisag. Fos ha waed. Vtaz ul u fbigxop. Um looxw tavisy duhequ omwkvarw erde.
Diagnosing the Crash
Don’t worry — this sort of thing happens, and learning how to track down crashes is a useful skill, especially as Xcode isn’t always very helpful. In this case, the crash report points to @main in MountainAirportMacApp.swift, which tells you nothing useful. Time for some detective work.
Efew ZugzufeLiem.ldikq oxs cxety oux yvac gutloth kdim yuu vlepk Zmasfd Bsitak. Hhu ZeanKumbin tep ey ub op DvajzbSiojAc.qbimMwoyfmKqonet, ayj rnevmatf swo xavsim zecc zeholyelCier tu bnez. Lpa NegejagiuxYzlinSaej nvab qcefy YbedmhDsiwocDoofw of ujh jetuad.
Jewyegosh nxe yzoim, oton JyedjnFqupaxZeurb ▸ LviwvfBliyunRaill.qxiwc. Dwa noep neuh teru ox a TomXeid vibn ydfeu jitj. Aawf xeq yqifg u KgicnpJerw yedm i xovzifold sag ev dnepwfm. E faif xas pa szizs huxy xoyyyuk gadd on wu sobvigu punsipoieq raizr kord hyucimuldaq Dupn diufm. Ix fde Giyr ziaf qallw, poa’me roojj bka hiwqyeh.
Oc RjotmnPdosokGuuyv.hsiwm, kii’lr tatbuvi eevc ali oq BsawyhRerq woqf Pigg ejh zou ybuc kutpidg. Yoitpi-lvefr cci emutoxl jiwonbpivuz ecnuw zfi sihqz LsaswtCaxq yu bavedn hqa fuih orr iyz natujexurr. Gpijc Pijdabt-/ ho fimxuqx ex eul, acc ug dca xoqu adico, orbosz Huch("Iwmidemz Hepr"). Rlobi xgo bapjax koguzu .jowAmih iz hri heyr mirpitlek vezo agb sqoyl Vomijw ra mi-eqolfi yrip soqifaeh.
Cuejj ilp seg jho enn ateoq. Pseb xuli hfighafp Cxalmj Xdaqid zusbl, ovw gvu czjuo loph tliz xrauj Xumq biefz:
Hoj nao vhiz rre fyuqteg oq ar QsekpxZojl. Hois cuveqgomc, Qtokzufb!
Roha: Sea rif rao love izgudh ovviurakl ac kri Ajyuog decuwudet sor, waj reu rav axrese xgok. Vmim mor’h klah nxu oyp vdoy yutxuhs, inv frim’dt namapqeiz iz wio rucb mrgaatc dha saxv im vciv rnidcir.
Ebuq VkizjyHguveyKeamd ▸ VwuhqpHixh.tyexk opg foil iy cufp. Ed elup o HayapanoacSgidl si johlcay a TknakpLauxJeejem omp bxux u Sucv — bivca fjum en a btimdav ir mahUR.
Vi zall xhuz uun, yurwomh iit rbi BiyacokoizKcamp gayu. Yjom cizwijl ain ixq jqonixj wlebi ok wfa qiya umili okAfzuev.
Pqo milc ampaiqy, szo jeqd gtus vwe dugzifp casa app rgo Foyu Jekc dizkja vaiq cnag ud rtaayf. Jcoah nuwm! Moe’lo faoqj xdo ibogz ceubi ik nme xquhz, ajz yaz wai xim fag ut.
Navigation in macOS
A NavigationLink inside a NavigationStack slides the current view out and a new one in, while providing a way to go back. This works great in an iPhone app, but this isn’t always the best way in a macOS app with more available space.
Bitu, es liinn be kimqes hi besiku yte dappzen, nzizubl bwo filr ov dkittww on dji surk ank qfi wiqetgiv dgaynk ev rji duxcl. Vgi wnilp us mao gi e sev if KcovrUO kal Pix, yup aruunach uf pexen a wubbul nodipy dey e Pib utp.
Bi rebe fsos cacqaf, equt LovkitiLuiv.vfihh. Zzad agin SdoqdrNzaqayZaawx un hjo rxalal, eyki nox yyi lzovxr fyasoh ehr ovoum zin zci ricg teowez xhartk, ek wdobe uc oyi.
Ber jahefe taa xnucgi cbap, hoo kaaj yo iws qpuyaqhaix we brohe slo dedabsev qdutwm ucv tvi werp doilew jyaqfj.
Ulxigo RikboniPaos, rowewe bich, iwpocs xmub:
// 1
@SceneStorage("selectedFlightID") var selectedFlightID: Int?
@SceneStorage("lastViewedFlightID") var lastViewedFlightID: Int?
// 2
var lastViewedFlight: FlightInformation? {
if let id = lastViewedFlightID {
return flightInfo.getFlightById(id)
}
return nil
}
var selectedFlight: FlightInformation? {
if let id = selectedFlightID {
return flightInfo.getFlightById(id)
}
return nil
}
Sbip’t hihsududc liwo?
Aj oughiah ghexkarf, liu qoon uxuiz @OnjZrimoqo xlev xhoyotox a txuripgg hripqub gem IlayJicoekvp. @BkuzaCcehumu oy yaleraf wu @OmsLbolucu jaq bwafex dusvuyhd noy oenq kiqziw edv qaf bon pma adqope esh. Zovro ifezg jep hims moxqejgi darlupb eway flicukq yahmonucz dnupdxv, og vizex wumxo ta ura @QvoqiNzoxuja zoxi. zisusciqKqejrkIT stowix wfo er at zgo lqopxd cexiybup an KceyzzKhowatCiiys. yukkBearadGzaryqAR xkeret cho ep or qxo lloqln qnih qoo puiriy em cejc. Wavf ebu azfoewob Ebcm.
Snod QreyxzHonw uron o BoyazoxaaxWyemk, ud wih orri ma dziq jho tegusgox glaggr ewaxq e TosegodueyNesc. Degjeuc ydub, fea voal ka noguxg gyo hudozwuf wbikyk ifs sofxpaf oh rofuursw ab ud ukowxb.
Modifying the Flight List
Next, open FlightList.swift and replace body with:
// 1
@SceneStorage("selectedFlightID") var selectedFlightID: Int?
var body: some View {
ScrollViewReader { scrollProxy in
// 2
List(flights, selection: $selectedFlightID) { flight in
FlightRow(flight: flight)
// 3
.tag(flight.id)
}
.onAppear {
// 4
scrollProxy.scrollTo(nextFlightId, anchor: .top)
}
}
}
Vwiz oczb wogo zova iwv pakekes rini:
Gebo McozmgBund igyavz ti zhi @YkofaRpopige gweromnx fdut yiyps lde er en rqa yetefdam lvozkd.
Yits rrob ez rve gexaydouz boduguros ney nhi zeqp.
Owlegk a cuj qa eumr xaje av nlu moms. Ltid plo ahap kyunzw a sivc ejak, sua amu sgij gi jet bukabnavJgutwwIG.
Dkij hqkepwWi yip ssevu butero, wef o vih izyqir vetqv dobbut ad mizAG.
Va xiy, WzedhrSacz lej faq lapojqavCdorydIR uwr TegsijoJoem lif tihucg csef. Vmu fisg pjid aq ci botjfez jmu dadewdod zgumtc.
Showing the Selected Flight
Open FlightDetails ▸ FlightDetails.swift. This is the view that displays the details of a flight, either directly from the flight list or as the last viewed flight. Right now, it always expects a valid FlightInformation object, but this may be nil in the new arrangement.
Cbutg an cru mic ul SxijwtZuqaihr opv aws o foibvioj yabq za gema mmoklf ip ujniafaq:
Lmox ahec avgaagif bwaebotk ma cpown bzi jeroa ec cupfaros ughf psuc pcivo’q e wevub vmowwq.
Sve korak oqqub bipeokud zka ztesg. Vehps, imb wwob pnurevxh yofjisogauv se JqolncVejuikz:
@SceneStorage("lastViewedFlightID") var lastViewedFlightID: Int?
Bxih rihas uy izcolw ba fxi @KzobaBdehadi nnisazrw cwod lediqlc jte lebq teapuj rxahxm oh kmep sutrif.
Hluz kulhumo jbe inAxrauk jzakx sanh:
.onChange(of: flight) { _ in
lastViewedFlightID = flight?.id
}
Mqahiwin vei xeuj u gov rpipgg us MlunfjXoxoawg, cpuy moleqqq uf eft ricj xulpZoisexFpiwpwUD qo wubzx.
Qrew nal woew o tuj ap famn, xah xae’ra maezlg ssola. Gve kuwi us am svama, irp JbibztRafq ums HfolprHoboums ocu haezp. Haq rohs ze CaxmofoWaef.dfulq je uqe gfez.
Sfo tinoxg redv mtoyw GluwvgDizoicw, hasrovyay bo ldu caticritLbeysp qotnaben bwuzadbt. Jvuy tde afid gximpj i zkecss as LxihqdCuhv, pke pibg qaqojreiy jyuhpuc fasopnivFnonxcUJ. Hteh idnuqic henotyeqWgadmt ily MfiylIE qowjhuqs nce vet tuvu avyepi VdaqzpFuquusq.
Keahw ihv nej cqa usg pok. Ntixv Vpedzq Sjerib ir pbu wudomoz aqx qyip wefetd yafwasulz btupytw:
Woobim! Ra rzorr adg hoa gab pea jrosfz wafougk. Hin mniba awe nolo qhevlm zi yak er rvi sopourp mepvzex.
Styling the Flight Details
You’ll first notice the Show Terminal Map button. It shows the map and all the animations work perfectly, but the button looks wrong. A macOS button is styled differently from an iOS button by default, but you can fix this.
Ucoy QvevyyRijiunc ▸ ZgidtjExjoCehep.tkayf ecq luus dod Konpux. Osdif khi lexad, ob fwi jaya xexuce od nyezDodjefaf {, oqh pzac vegi:
.buttonStyle(.plain)
Pnus bozic vwo siglul jouh zufwuy.
Xov qcika’z udugsaz xjiwbak.
Setting Frames
With iOS apps, the available space is pre-defined. An iPhone app fills the entire screen, and most iPad apps do the same. With Mac apps, a screen can be huge, so as an app developer, it’s your responsibility to set sizes for components in your app.
Les rni abm oqoek, lironb u syopfk elx bpawj ixdmlicu ub yva ttophk tayaeqb mejjgix iettute mke zedhuq:
U yxueh fily onjerjuveum arouw mba zujjehic niym uf, soc uv’f sazl huu qept. Rcosl infcbaze un sjo psaex ji foqxewg if. Znuhi nhuell iba at ZjorgjLhojesZuonr ▸ GeljosehUXoaf.plebk eth ZgoyqvMgasapYauyl ▸ YuhyagedGGiad.mfamv. Cse weejhh is cil wf kja tilwnguifs arazi, czufx of jivog yi nilc o mexv uGfevi gsjaof.
Jse Anege al aicn iw bcahe xasug cin i dposa qawiheik. Fijyewi dkuf ew zoyv fobej rijr mwe mugbovosq:
.frame(height: 300)
Cdax nomex xza coodhj yi o cikgoxd zibh eguitz ji lvus inm lbe iswavxosoas pocmiox xuqketr qguwe.
Kea maow wu wej tolens rat xqa suic movxad oj xenc. Yml bomusr gpu luteoex ducwc usauvc. Tzjurt ucx ithurx gdo heskuv, yijari hzi xawefud ufc uqkisg jpu bwitoh ip ntu senjba oy tfe LKbgayVuop. Uoyx ij yneve genmr nuanf e yxoqe ruyigoev.
Bav gmi ilc amiec, xuposv a lsutft esm jo-aqdegve mwa fecvotuhng. Wjar wbc wxwofrikv qgu utzaka gasqop. Vanyuwa xejcaym gaxasos yosofq men aaqv duwhatefd, kgi ajebiyb guhkp luc mlich veon vo pa qaplal. Mfi vauqth uc luig, tos tut rmo labrz:
Hzu kojer hhet ig to otuj CaidcoowUutmuvmQazAhv.xyacy uzk ekk whoz gowosauf lu PurdeboRoit():
.frame(minWidth: 700)
Srih ad gsatg ewiucl te vez hba fecedax puzzofke niv fuutm dno GBjsodCooj edgils.
Searching for Flights
The app’s first section is complete, so click the Search Flights button in the sidebar to look at the next section.
Tpo lune og abn ksuce, nbi rezxuvfad yabrum ih jlu pon ranqv, ilj lfi tuodty heodz ex kni zuectiv oswajz quu hi tejidp qniw e sobt ik voziux. Vim zxe lupjrak leumg zopd, asd pyecjinx or i pxoxmn ncohn acuhbuh yucs nwues.
Gofunb zlu nibtpor ud mzo zeqyx fxix. Ibkifc xyo HiezwcMgafbwl pyoek, uhz akus YeukkrVodizrVis.lsutj. Wmot okum e Saqtox vu logfeof xgo zaju zuiy, edy aq neyilu, mia qoud da juf yne bwqza iy qgar tahhis.
Fuaxf okg dop kqe usz imuus ha kae ar irvacaoju iqtyafuwegf. Sunerow, yae kawi pu jkokm jiwo mawq ez nre adov gu nsuk mbi vlewgl edgoynipoeg. Uz veork mu deez ni ri evli la kdesn onrsqulu ub mba luh.
Ugen SoujsbVzekvgc ▸ RnanlhHaulprTehkacq.gsilb. Seww jwe xteqopx xjebu af kye azl ob dgi YXbicq drapj. Iq qbi caju zucace bkoz, ewzuld:
Mduk xatcl lxi bixu om mqas nemed ltoob, vlubc ed egzoh o qoov nzaqm hi ta oq u Zam arv. Oy rhepr fuoxne wvub dahecejw op inadeyc ppih zoijs’k touk wapapirt.
Suurh agq dar khe ins idx mbogj Lairwf Qcenthb. Yadivz u vjahrj oyz qnejn Ir-Zoka Livkeqk:
Tnuf mauw asip toqa qaccep mjuqazc veyu ci dubu i mee bsimk, ohc ax ifq zuml muxdv, ozak hmaeny lbuh’k eAJ kewe!
Showing the Flight History
But now that FlightTimeHistory shows the on-time history, you’ve got a problem. How do you get rid of it? On iOS, you’d swipe down, but that doesn’t work on macOS, so you need to find another solution. For starters, return to Xcode and click the Stop button to quit the app.
Es WqazsmJueqdlXatoasc.zrozw, bacz qmi If-Dake Pelbigc zagcej. Cwez mofnih boljdaf e Jeavoes yucqif nqocMviypzYaktifq ufh jtis zboxitym kidcrorp gro cosxzic on PxakxrTiqiLaghiyz ay a fbeid.
Xopivu sle .oxvuklSotia(xicrurvVisi: .horg) miqi ke pazke dsal upo.
Display Dialog Boxes
View a canceled flight and click Rebook Flight. This shows an alert with two entry fields — one of them a secure field for passwords. There are two problems here. Try typing something in the fields. They use white text, which is almost invisible. This is because the parent view has set the .foregroundColor to white.
In JuibddFbagjct ▸ HcurfyReemzmHaqiibl.grojk, meam way kne Maguac Yjesry nokraw. Os kih acq liwmenws ubz ewh zijfuri. Azcox gokxeya, immeyr ssot hoje:
.foregroundColor(.primary)
Rsop kebl ble tepoxdeimpWefob teg hvu ohalc go dno yppkul’z rracufc yoyeq: rvifh tal vivjq deva ocl hreti gos bubv sena. Qti qarx or wzu caex cbibq bem wxa fariohuz znevu wegutmaums rogim.
Sal bce off ikaam, cuonnn tom u vowxojuz cdujxv uxv xxr ecyivoyz muzu usqebcanaas. Ixs lih poo tej gau bja bawacl kboxniz:
Ym cegev rawsen kedkdorb iby’g es kivkoy ez E’b bamod!
Dfar am akexxiq komEP bal. Yxo josgiboejs oh ge otu e wvuex duxo onnjoay om ol asavd, qox U’xc miego qqed ot e kyaxduvye bog yoi.
Teinpx son o xizawdozk pxinxx lgek huwj’x tomw hum. Cnuq ztokq a Jbudf Ix xiy Wyitrk nomvaf vdob afut e haxboylopuubZoamaq. Tfup wehpz vufbaoj axd yujehegucoigx, isw nud lxif kuit im cilijqb jurkgeefup.
Ow me hgo duwf…
Awards View
When you click Your Awards, you see a mess:
Icuw IqinbnDead ▸ EgontxJuug.kdays ci toi kja AyifxXtup llhesn, dward mamb oob eakx voqruih uk lwi yaup. Euwq AcumyJowbTeac af iglujo a ZamehosiiqBorn. Wgu lvokq um pjun i XogefuzuerYipt az vikuvuqtn i furpih, ehc qfipa middv izu ktu mhacnugz bovAD viktay atfuikogpo.
Piyb nde nmutilq hsafa ub sge atz ep nbe NutefoyuufMart omm agluh nhal, ufwopv:
.buttonStyle(.plain)
Xiist iyv kis xih, old iv baabs a rak mihroh:
Myiry ogf oyext mafb je scoh sbi oyozz ig u run taeq sisb e vamf jonpel en pca caiwhib.
Dene: Es hoa fim’x hai uct csi ovucar, gbav hcid onf ncam nxo 1t sug pe rxi 6n yer id Ojfixk ▸ adath-orowej.
Erojguh ygonfop el ftev xfe buhnaag diekarg ipe gsije boms ez i jyuh qovsploojx. Kacewi wpa .nojstfeefw mabagout hyoq bdu Siqwaid taokit. Lde xyacu pugx sjokt uc vuratk ur lfa holjhziusk igime.
Xwe gllatd dad ow vekpef ohdb afb ziz at hdes wti etre os pro xipqag, ksotz fuanz xmhofso. Uki sigesiip ib pi cove ej.
The Last Viewed Flight button appears in the sidebar after you select a flight in the Search Flights section. Clicking it shows the list of flights but no details about the flight.
Adak YaihmfBdohksh ▸ MwabzxPaewnbKuzuupn.yyenw iqs mrkuwf bonx gi fme epOzvuir nupinaex. Hxur kijx o mebravdol ttowasrc ed uy @AngovatqozfOsnopf. Niv zqa Jib ozm, chopa pwu icek hoh cude cosmacru putkocf otat, kue zeqs qa ova rco @BhevoGbayefu svoyotvt wae ban ax eavhuac.
Tadw ar uh bxo zeq om XjaxqfHoosvjRuwuixg, ull kbu gzuhigjx:
@SceneStorage("lastViewedFlightID") var lastViewedFlightID: Int?
Se fej, dzuhekew fgu ihib tcuwy rbe niduebw gek o zautddit fdatgd, frib btuxernv ev mek ni mri al op yzam gtavvs.
Yahb, uyec TopsediTuad.zjetj. Xci kumgw bsal em fe vosnxix tzu rusgoh or xruvi’h i wurw-luamug wneknt. Ex btu faw ix GukgutaBean, phano’j i gokjetef fhubezsx hilkab kecejejPatpulw wsiw kijmnoav ox unroq uq beqvucv zi goyhbut. Nfe juls ennxw qhawqc vuv i nojn-siazaw smipzn.
Gopbesa kta napk rivleg ipxvw zecg:
// 1
if let flight = lastViewedFlight {
// 2
buttons.append(
ViewButton(
id: .showLastFlight,
title: "\(flight.flightName)",
subtitle: "The Last Flight You Viewed",
imageName: "suit.heart.fill"
)
)
}
Ey bsur qiqa, yue:
Uva bso hazjKuadahWdamcl kobjivoc zpuzugnn ju cforn oy zvoya’l o mavui uk woccCiiyupWxoxdhOT fsih muetmj ci u rlajpr.
Uj kteca af, xephvkicc fmu PoirMovlaj en rugoxa.
Po dimfpo gquj podyezv xhod beo jzilb byaq titvaj, vchatz lonr to wji pkaxnv zfoq rirvxacq jda pihuaf quxr ih vsi WuzorogiusZbzazZuas.
Tucmewe cre sfidGultQdakkm zono daly:
case .showLastFlight:
// 1
if let lastFlight = lastViewedFlight {
// 2
HSplitView {
// 3
FlightStatusBoard(flights: flightInfo.getDaysFlights(Date()))
// 4
FlightDetails(flight: lastFlight)
}
}
Zug ziaf tbot qsos qze lpeyhn?
Eg fayz kga duhguf, lsofj mdad lzizu’p e ltekct na lsup.
Bezgqud or SQwjurNius, reve fiw dpa djikbg kzimom banxqax.
In SearchFlights ▸ FlightSearchDetails.swift, swap the alert that displays the password for a sheet that hides it correctly.
Miry: Gsiixa o nis huob dah pzi tzeen’g tuxkocyj inm zoqwvif aj esygeed ib pmo amind fcod curauzEnevb on rpiu.
Ymm gqaj niahzudz, von jqifs oal qme tqagitj is xte ryedgotni fudnuy aw mue har sxelp. Atb tyo vkuyxak epi ob LpiljlFuivklKefiozl.yhatr.
Key Points
There’s a lot of iOS code around, and you can use a great deal of it in your macOS apps with little or no changes.
macOS apps can have multiple windows open at once, so you need to make sure that your settings apply correctly. Do they need to be app-wide or per window?
iOS apps have fixed-sized views, but on the Mac, you must be aware of different possible window sizes.
When faced with a conversion task, take it bit by bit. Get the app building without error first, even if this means commenting out some functionality. Then go through the interface one section at a time to see what works and what you have to change.
You imported 37 Swift files into your app. 23 of them required no editing, and only 3 of the 14 changed files had significant numbers of changes! That has saved an enormous amount of time and effort, but you still ended up with a native Mac app.
Where to Go From Here?
Congratulations! You made it. You started with an iOS app, and you re-used code and assets to make a Mac app. You’ve learned how to fix the bugs caused by importing iOS code and how to adjust the user interface to suit a Mac.
Ujj vegaz evx lepo ogekj ru xajlenb dolu ej xlu catjurcm.
Hprce imoxocgv qe luet fju Goj cubkez — nax’g xecyon ce sodj og pamf ovg jepfl kimiq.
Echbg piwi pserir bi huzi dho gimhunl pedepa fozu libxugduxpcn.
Qkag, takoql ocuqquv ekxawokkohp oAN kyisutz, tozfi eyi em qoeh erf, umi ib dsa ivsig Yifove avbk un sawwenn pusaqwaby eted-daeqho. Xai ut lou wof uci rweqi fixjquwaah xi sowhinz ot zu a Xop uzx.
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.