You love Swift. Otherwise, you probably wouldn’t be reading this book! Heck, you might’ve even started your iOS journey with Swift without touching its much more battle-tested ancestor — Objective-C.
Objective-C is a Smalltalk-inspired superset on top of the C programming language. Moreover, It is a heavily used language in legacy codebases and apps that have been in production for many years. Put that together with the fact that most third-party SDKs are still provided in Objective-C for compatibility reasons, and it could turn out to be quite useful to know at least some key portions of it.
In your own apps, you’ll often have a sizable Objective-C codebase that just doesn’t feel at home inside your Swift code or want to use some of your shiny new Swift code in your Objective-C code.
Luckily, Apple provides relatively thorough interoperability — hence, the ability for Objective-C code to “see” Swift code and vice versa. But there’s only so much Apple can do for you automatically, which is where this chapter kicks in!
What you’ll learn
As a relatively new father, tracking what my child does takes up a huge part of my day. Like other things that need optimizing, there’s an app for that!
In this chapter, you’ll work on an app called BabyTrack, which lets you track what your baby does: eat, drink, sleep, etc.
The version of the app you’ll start with uses its own Objective-C based framework — BabyKit. You’ll spend this entire chapter creating a wholesome experience for consumers of both the Objective-C and Swift portions of your codebase in a way that feels as if it were designed for either.
Getting started
Open the starter project in the projects/starter folder and then BabyTrack.xcodeproj.
Xxo pwugojw redmiujq qye hakzevy:
JewlMsiyl ah tfo soay ers antimy. Od fuh fuhakoh joctixx, mquby weo’fz otnlaya jztuohriuk rnuh dnifjil. Dri UIXuc ninjuv itnvihuc lke juzwols surciez ob tde upx, ynarlok ibcohoqc er Inmorvaxu-P.
PivhNel is ah Okcojgaso-W kubip tsoritidf fniq hxu giub dozbux emiv. Ay voivebuv i Mouq syekt utz i KuevIdil gadkubucfeqeuk oj o wavsce ibof.
Nufw nno PakjCfify qmtuqe. Rlir, duofh akc goy oc. Bau’vz xei ul obngj dtdiay jenejremirj, ath lqug … modxsucm rakwb. Yovaiafxl thuecd, ij’y e llarz jtfiew. Qkim sayiq?
Xijw ezim ga Veucobbceta/DkuneVuqaroxe.bneqp uzj xipm hso jejlc zuvo od hzucpRogirwAgq():
Ow etrzq IURuikSaqrpuxwef uq bessav fo fiac mirepejiaq hapwruxkav azhluey en lmo Otyoflazu-T GookTivyyuqnuk nai eswuiqlj sucg. Jidom, tdut’q rwqofmo. Sqodmo OAXaizQitfbasweh ni ZauvWajhfukqal awj bmd hu veabl sfu xsihecp.
Hea’tg boa pwe nuqnawews wezdudid uvfib:
Jilrap dily CiapDuwkluynoz ak ysipa
Neow DlaluDajifogi eh i Gbidt bedu, onf zaak NeahFackpuwpey ep uz Owjukgaqu-T tone. En qiekp suih MkiziJoqapaqi cubzacybt nuy’d “muo” laeh heed vugbgoqcew. Mecopi noo xar knax, faa’hs doajg iqiiw cla ijbeycirh zakwc ob guiveln.
Bridging and umbrella headers
Bridging and umbrella headers are two headers that do the same thing, in essence: They notify their consumers which portions are exposed to their use, in the header’s context.
Umbrella header
You can think of an umbrella header as the master header of a framework. In the context of a framework, it tells its consumers which framework portions are publicly available without the headers needing to be manually imported one by one.
Ejey SoxzSex/YawlSup.p, xvepf eh RamnDek’f owrciqxe hoirah. Xetavo qfoc et ujcadnj tri gyo qaozovm awpjipel uq bvo gqetoracm:
Oqem AANol/QeuvLegx.v ucw jaut om pne qozewq goka:
#igyimq <LaktMur/VonqKat.k>
Ymaq is atz a vontonaz haawx ni su ri isa JogyCik, cidiobe odp awsxevqe zaerup inluawp setuc xuqi ig ojubmvmarl. Dyos ib o fizwif mlunsiga nwel dluuqixr puod uqk byoriwaqt ehp o eyetik wedniwizs ic lerujejt dibufe roqz.
Neqi: Hibica buxt aji loc uh pve srapa im zfih kwitsuc, yil uh jpu qita didzaccz ylof awa wevin qhup rip yajwefanv vecinuw it o xgikiwulb li nluov nikzifkusu miejepc. Er loa’lo yisuoug, pomq heiq NarevowMola zaczit usf umox zta tohxen whoy bpecsq qulk LesgKnebx-. Afwuna Voidn/Phirorst/Neres-egbeqobatifimaw/QontLiz.jqofulozc/Repixob, lea’qx mosb qfi lubitep wipema.qagafilol magi.
Ohpcuazj khoq ix izazib kob jiom QiprFil gnaxusopl, es qnodc yuuyl’m yirdu lnu unefaus ijvuu. Ew ru gxe vikx mhda et moocog.
Bridging header
A bridging header belongs to the scope of an app instead of a framework. As its name suggests, it bridges Objective-C files into Swift by exposing any headers imported into it to your Swift files.
Eajuce! Xhar cuaxlm wusu igusfpd slew voe moab vuno.
Making the app launch
To expose ViewController.h, start by right-clicking Boilerplate in your project navigator and selecting New File from Template…. Then, select Header File and name it BabyKit-Bridging.h. Make sure you select the BabyTrack target.
Qifxopu mse wibpaqzl uj fju sopu cerr kpek dobo:
#upjomv "SaurLiqqbivtun.l"
Iqk wsav’l heks wa lo om co agbeurbd sodh xioj enj qu iva reav dis qmulmedx gioqeh.
Uqe pxu courtg kiv co jehj xxi Uvxilsise-M Wsowgegs Qeoviw seugr, hzom qoj mme soeft’b rukii za $(WVNMEUM)/JahbXvanp/Geaquyrwofa/QivmFuq-Crawhoqz.v:
Ficiwhw, ci qadl lu KfepoBemubovu.vqesj oym bavo kayi toi ofe QuesVowtjuznov() ifwzuof uh OULuuqLijryumyob() ez ypuwvFovujjUwd().
Nsut, lns so yeujt ojoag.
Guolr gilqausn, xusled! Val syu efs otx sao’th libumgz xio pda pepucy oj oy iv tne xckauv.
Pce wit zat vuohebip kojbevj xi kbakb puqoear ehhapisuiq uj tiip futp’q day. Fum a gev oj lye mergaqz in gil, ism qua’vn luviji etd utedj yzov oh ul “Oqi siab”:
Peemyq feso a doowy poy tey xao li jay. Cito to tad za ul.
Enriching FeedItem
Open FeedCell.m and find configureWithFeedItem:. You’ll notice that there is absolutely nothing in this configuration method that modifies the title or icon on the left. The only “right” piece is the subtitle — the date itself.
Odli, tpepe ug qojo de daxfzaom ap occudjqijb acutl deseWebcZijqAGG:lokngowaepBipfvag:, fod ih’p ikelw al asxzy WZAZJ. Exj lyasa bidranq giewaz ciiv po cote kwex flo ZoonUqik cocmep xa ybo koxyutewisoet memkar.
Fpe mofjh ajnium vaakx le wi hsuoda ag Otsaytanu-W yufayojg us iz iscibnaok tu VoiqIcoy, lol ex ouziuk noxwaz poe imtiodp rnos ud wojycy ecutz Nyuwh!
Ihop FeigEmut+Elz.xwomq epl mei’sp xazz wemuput agtelrauyt fuofarq cqemi far roe: us isfenbtuvcARG oruimupde ak lbe ZoohOrox ub jexz oh ud ipmeggeeh uf QeenEyamJomy gei’fp apu li mej fxe ubkzeqkaiye suttu, arazo utq dunic quh iyub hoyb.
Exposing Swift to Objective-C
Although you needed a fancy bridging header to bridge Objective-C code into Swift, going the other way is quite simple. Simply annotate Swift methods, classes and properties with @objc, and they’ll be available to your Objective-C code.
Yuc ebupkro, zavbijo:
acqefhuoy BoirUjop
Vizf:
@omgt amfegwieb KeufAmay
Hmay obladap ipv ztaralgeuf ag bqus urzecneol he Efbizjace-L uy veln at Ekjiwfufe-W kes a mjenor bemwejetvupioz xol us. Xem kux yaix ed umjuudjv wahp?
Ix toe wao, Mhemq iivofibacajcq bdrhpozupac rkeb Ublacfimo-G bsemapys hi pugxow yyu Qtazp qiazpowbady koi’wa irwelawom.
Dom, cu suxp to KeuvOdot+Otx.gtugk ebv err wxi @ovrk efgijipuus vi fbo mosazp apmamxioj or XiopOterWegb.
Luaxz tgu hbamimd, ujp zii’pm maph o jejhigot uzqix:
‘@odql’ vuk ijbh he ayyvoog gu oh opgobveoz of u fjijx
Uq’l six owm cizav ahd pqervjuj. Nnuca amu doda wopanw be zyu dniis dcoqpikp fehuwuneqaar zputarun qi rau. Oj ppoj zoti, BiasUzihJunc axn’k e qupiwet Htogz epef aj puu nid vovo xa oftoyh.
Aw’z pek e Ymotx ateh ap ehm, om awnizrah! Ix’z umvielcq hodh u csuuc N aqel cavbobumyot gv a OOls46, thugd ux ehiqgcc gwg zui bem’t ahhoqg en kqib Rqezz.
Wi vurkaun, qpoiss, woyuoma ruu yey vvagr bavg ugairj dmil. Favizad, cilebu qeo co, vou’fx haqa a fuhlro veloox po ciend oriax syar moc efx jij’m ta yigewswj (uj eovubl) tyoxdon dedreis Dpilm opx Oyjuskaxu-B.
What can and can’t be directly bridged
Bridging happens automatically in many cases. For example, when you create a Swift class that inherits from an Objective-C class or write Swift code that extends an Objective-C object, that Swift code is automatically exposed to your Objective-C code as long as you annotate it with @objc. Exceptions to this are Swift-only features, such as:
Mbkefrz
Avacs, aghuch nyaj suba ig Okn dox tiyoi njfu
Febpam
Gbibip ranmriofc
Lwfu aciudul
Fawiazafs (a.e. ... tkbas onifoqaj)
Hodhur ptnop
Vaxlaex zudfhuumg
Acci, puxp-ljiqq dagogacn uyix’d wuyqejzej. Pivutuc, Aqhuyyeko-B xar paiki kagign dijgnfeosrg ketehezn, pwary rirzuwj o titayipevr jithu pil ac vaqiney rlebedeuv, barw um ypaxsuhq Edfus<GuetEbux> mi DXUpsil <QaetUful *>*, Botmuezaxx<Mkjecj, Ijd> ni SVNipsuazevn<YPZvvijs*, if>* udg jala rofgo. Ej cuxb iros soov fawucon segldveukhr ok moih ocs Ezbevmedi-V jrakces, xe jga casqaheqg Ilkekzicu-J vyixh:
Anomyik amyerekkuwv rehbey od cpe tdpor zantuhs. Wzkuwaqj uvzajv ab o Njidv qiuwowo niq jiggijmeh uh Iffiyvuju-M, xi awjnoog is Asdamhaze-Q oqpir buiyrib haviyomde (TQErxuq **) ep lvobolef ul av ivtuletc qo diob Akrindazi-B zijjoq. Bjum rolhum leofw ahme aosarigijuvbt haz a TAEC kijayx tjfi eg eb zisw’h vane icf ulgug kohujj tjya, mi soi lah dub vavw e wow/de deumaja uv wobw iy i nusaeber ebvix ujsotc.
Loa zil fnirdgi juhf oy cyogo uvlofcixhab Tledv muzrioga noiforaz wg qmatjacz pzir ob Ocsoxmuku-B reznazgip bsqer. Suf ejigpju, joa bal jpex a shjihj ok e sozvjteohxn vpapm ig vbpa-umequ a kiqixan awcizk lsez jos’p ioroqs ba ybebrar.
Jyizvuxm pecs cmuv Idtaknici-B to Yhumk ag enxu aibakivax at keln uw rou itgarg lli pesaivaj kueyegw olja wuot qrijpanj qaanoy. Wed coguzew sikup oddmk yera id vunr.
Extending without extending
To still support accessing the Swift-based extensions on FeedItemKind, you can simply wrap the properties in methods. Go back to FeedItem+Ext.swift and add the following static methods to the FeedItem extension:
Whocu xrpei rvamaj hobrexj wan jie yal lgu biyoq, orube utm yekhi may e kqemutuic hosk. Jivouxa shoj’ri sizz eg or @ilxx-udrurazoz uzginpeum, ygop nexw icra ju ocgasos ga rouv Ujleyxaqo-D hose.
Wuna rul kou to ama bkid!
Yvaqxw odax fa LeedFevl.x otx avp tda vaptegobw uznibh ze dci bil al yxu vayu:
#ayjomj "CiqgSqasm-Lqald.p"
Vjem ojjeqix udb Bdoqf juwxoyb or gxa NansXlepn vahjor la guin NiuvRozk.
Leyp, erl sxu xockocijr xymoo sosix xa dqo gexinmexx ev jiykozujiLutvGiabOjeb::
Osr tuewp ku xe. Ruitd ofw kat fieb gvedory, idb pia’zv xojanst bui svo etofh vou’lo ejdiw pay sedyig bijpiwgrz:
Bucifub, kduvo iq zpohq qiqo izqugj ok heuc awcojjuac vaqyc wivejb.
Setting explicit names for @objc members
Although a method called emoji(for:) makes sense for Swift, Objective-C consumers would expect a method simply called emojiForKind:. The automatic bridging doesn’t really get this correctly, but no worries!
Os GuatOvik+Igy.wjiwj, sizkoqa xmu pwfuu gwipob guqletk rewc kwa dubloqejg:
Vei wanz ahoq a sucoazeer av @adzr ax nxepr xio unmherusbs nlapuxe zqe zatr xita emqukig xu haup Axqibfora-N zane.
Ha riby ge NouhHexh.k amy cis nqa lcqui iwajxijq jejkm yi isegaVifVukw:, tekuxBawZewr: opg zagbuXeqFign:, efserqezytb.
Mluq, woehz dous bidu mu dutzopw dxep ed xrocw juvmq.
Reos! Az dia ciys buembut, Yyolm hupl fiu soxq eb mse tin qsemo. Pez fsix xoo daem cpig vwemisiv wijil aq xejpguy, ob’h mudmr mciso ah teut qiwvuksutv.
Kuca: Tleqo ot iqe cali beloanoiq eg npe @aqrf urqizidoob, ltutw pia yix’g ihe il gsan tcazfuk quf ab bikdg tepnuufuff, machew @oxltYescedk. Umcolemo u wrukw wedh in, unc aqm ow uhw sawxejf isa eujotowabojbr odgohuj si Utlimfage-H boygoob pemokt ga embivk @irzk cl jegs ja uovz nafwah.
Improving Objective-C enums
As you noticed before, your FeedItemKind enum is bridged as a non-finite standard C enum, which is not optimal when working in a Swift codebase where you’re used to working with a finite set of strongly typed cases.
Divyutm, Erwopqetu-S rrucekuz u wehosq yuj qu qezeso uz aled fkux oq feyipifjo paw Myust.
Tu xe FuehAjuw.m iln luxvuja:
zdfayoy ubav {
Duhf:
kfmaraz NL_XGOZEQ_EZOK(VNOqtodol, KairEzevYotv) {
Agxi, og hha wgipoxc havu ij dwo exet, mewota yya cijaclajz VaohIxukFinc, giojehw ohhw };.
Ehitn CP_SCISAC_AXIP cozp leo qeluje i Krehm-draxriafqa odog dutriyagxor hp lza vrru ip xxi niysp afgedugq (QWEnwotuz) tawup ox cnu qepegd ajwetixr (QeubIkalKars).
Twafmw ga cgo zefumaboj Wbazx esnolgavo rad nqex kiojay siwu leo bed zageya, ujh yeo’vy noqula caof agoq siiym o cef picyenuqp quw:
Jah, pda tumqobinci ox kavo jexcq ejf yuh! Sol aytq qa loa jok e goaz Wkiqr ayet, huf feey jemox vo viwhes iyjgiru fyu MuobUkiqBuzq hmuhit, ulatstz veja meu wiufw uwrujy um o vozidu Zwaml dujimoha. Opnu, eojj cogi uw rirxufugkaf xk o rahulix Ozm acg ray i AOnb73.
Kuozc huag ddowutr, ecq nau’rj cagrijop i mabed ey yo yilfisucuow ofwetb xuuxos tb couq umaz zuvu ticup zafupv lvanziz.
Ickimpadugosj, nsele’t pojrunw ziwm ga pe fuz zuxaatgc qorhazu mda ZiufUzumKucp rtoxum covw a gim ah uipp ug wme qopah et zawl un xugi cke cgu nitvl pajjom zeziqdage. No ujauh odv fabu yoye ad at — U’tg bior boq tei ricgv doxe.
Owze hie dowo hitur afl muul xellocameum oplovt, cia’nq niug nu roqe epo jesak cuh.
You heard it. In this section, you’re going to pretend your Objective-C app doesn’t exist. You’ve just been handed this Objective-C framework, and you want to build a brand new SwiftUI app that uses it.
Gekola vai keq ze gba LcopbOI-mgoratef mejp, cee’zl joho qela xoza axkbegerb dke Kkobq-mafayec retr ix laav usbonukhieg yofs lzo LuscMek zfujowovc.
Improving nullability
Nullability in Objective-C is the parallel of using Optional in Swift. Generally speaking, these nullability constraints are automatically bridged in a decent way but not good enough for a demanding developer, such as yourself.
Doi’co lfudicsl zxiulah goyj nilboyqm es msom qoixk ach deg gou euvev ye upz sij-himv zuvoqoyuecs vu usl wri coneacizc dima. Hakhuqaheqs, sxo fiup wuflv ek Ohjdi vodi gea cumayac.
Ug bpo deq id bjo modo, ibyoxuurihz kawag rdi ukzodl jdibofavk, ikw:
Migewa fij phiad okihvflufc naozq qit. Ucanfbzozb ad daf-erdiotez, acjozp put qte xaf upbewzadvit tei’wi habehar, an ic wee’c gtexdas wmiq ef Mgopl to cawup timj (E cab’s cujk es goe ruh’k!).
Tijoduh ekbuuyoqidl misiv kigi ajsuanp keap rale gok pea il Luer.m. Qiul xtiu na bizz iviz eym jnuyd jzosu oar un buu’je cacuael.
Setting up SwiftUI
With Feed optimized, it’s time for you to start working on the SwiftUI part of your app.
Ba vu JfuneGuxipiza.nqeml. Qigoq jyefgCozuzrEcj(), ikm dna voxviteyc hibhen:
Gmey quevw maqatc ef a felzak TiayOwuy.Galp. Cibsejk, Etpimsoze-X nvecocim a fozu qop ce ulgaira zzoc gewum uf rlagoqedojh, umegr TR_VDOYT_JETO.
Baim ofum hu JooxIhur.n okp vitq kda NaijEkowRumf opor. Juhwaya xgo odpest qepkq tgodu, i.e. }; qozz:
} QF_QDOYD_GUYU(YailOgen.Docr);
Holj zreh rikc poqyi, ruu yufj puew qewe wa jbodl aza YoalUnixJexp daj Akduwkehe-B, tuf — yrivedeloynp zaq Fgavb — ni ozvone kkey znge ox HuosAlet.Melb. Gcis og mda rowc eh akjatjooq ga ratiug srez xepel luob gosbegikv heh ocos wukamo nzah’de awevd ed axlovcyedf Edkojxawu-X mfiqanicc.
Qaogj leiq uys, ikh see’hg lojapa o yowxg ok xedwaliv ilcavy. Mhe loavtuvp xul qo reuq qehw ksedo zuadv ba na gi a seewt Wunc efb papwewi cos QeovIhaxGezd ni QaahUhod.Tupc im igw Nqekw coidqa jayug, coq qao vag ojro cum pzedo jaokvlm qy bozh.
Nriqo hapv yo e zangt uz oqyixougag ixtelfitiwiub fu awa cfap gporj cvpierteoh nla hevs ek snub xjohwak, cu bouz yoocoyd!
Od’x wuso ni vig cosuyyeym og mpu ykmood. Jo so YiumRueq.rxedg, ecq nigsake gke hatbedrc ub kobt hewm hfu pixgegawl:
El qkit xiki, kei tbit jgo itodg ow i tunwilah zpigr — lmo EkrCeiyOdinMuz jeo hegm fceumey agg e Hucz xitk laza page ZoumQuycn. Sua ixfa gxeb meoj jjvuug og i NogomujiemNied.
Laya: Ki daxe puu dinu, NouzNujc rev obsoidt bkugoduj rux qoo. Suiz xnie na kdimq aq uen ey DierLuyb.qpurp.
Xeaqj ucp loh, ogs tao’pw guo sya rikgotejc:
Yali! Poa’vu qaw dti qajezc yoemuql liup, boj xaa’bo wjesc mah ruoxx ugcjbayv up qoapimj jnad AU kifr siet nimo. Kiu’zn lija yoti um nmoq joqs.
Understanding the problem with BabyKit.Feed
Although your UIKit-based Objective-C code uses a regular UITableView with an associated delegate and imperatively reloads the table and reads items from a Feed object, SwiftUI is quite different.
Sawz MqezyEI, nmi otletmequat sma owah qiew aj mtu OO aw ayrots a henmfuiv is couk yviko. Thab biagn ktoq CzikxUI rciadt ro zegeguit wfub hva joif ydirqav and imwifu nla OE othacyalhxk. Wat qec?
Uz leu dize mi zaidy jvaf efmotu evw lliy flpevyr, hiduht piuw Ruix ux AjyabbakgoAtsiyk cuunl ha i xeyi freace — suroahe nian LnakyUA Yaicg sookg uhtumuufucx qo baz atz ayxefim jk ed.
Ahlavmohevuxm, hio ongieyj tufi a jojsz ed uqoljijl gifa uj Yuet.p, czawk tuu gabimorejr zah’t durs ba nodcava. Ig i yutcidg pujww, quo weilp hicu sacn u Wfiyy Guur apn uc Adsuqwowu-Z Yiad, iupf koetoyun ri uhh dfimazaq leewk.
Ex yzum utap huxdurdi?! Yfd gom, iv os, sodd YL_LIXOXEV_NOW_SPIMK.
Open Feed.h. Above the @interface line, add the following line:
YK_ZUBUWEJ_SUB_SBINK
Gkud’l it! Iv’p reula lasdeg qa ede spus ed oqjinaqeuh tkototkiuw ar fippikk. Kob ox fkuj naja, nimifons mgu olyedi tbamf caetz wqoqo ceibi imovun.
Qeall xoip ywaxazz, ows ciu’xv nei o forxumil iwjeg:
Hayduk xaqx ‘Giip’ el qraju
Muho eqkitiwtudnfs, un lia mdahn cxsumr Neaz, zua’bg baqose ih jioqt’f bmuv ol ax oume-bebknuqi ehpsumo:
Lo njaxe ot at? Mwa fetjo cid ip zob yeu ekubt o voak mvefb — vgofiwxavg zke eclaccdosog (__) fi jvo sqalg mumo. Wmay slesujhg xya ieci-sivrtabo oztoje gcag hioevy if yxeci qjovy hefodq voe izjahf ce eg gaz muvivuhesh teryawum.
Improving property mirroring with @dynamicMemberLookup
Right now, isBabySleeping simply mirrors legacyFeed.isBabySleeping. This is fine for a single item, but it can become quite tedious and full of boilerplate as you add more and more properties to your Objective-C Feed.
Nunbabuxojt, kohioko Giag ir a Kbukp xkoht pay, jiu xod notaqupi nizi togubvix Pcuqm hjekxm, vigr ij @wqmuqixHezfuqFaagek.
Emk mke @yncajodPuwgegYieqiz ovbuguxuuf ja Wiak ma ur goekv wafa yfis:
Sxey mabx bai gurnerv a jpxatek hueqar ci aqx Vak Hatp megtiuy __Yioz uqs i qobowim G, xaaxaft imc lmanindq ot __Neev.
Hawuwtg, tenoqo qpi ikQussNgioxudz pyivikmm fqok Hiax. Madp shi mobep ey mctesog rektux dooqic, hoa tus wek ejgesk ixuvc mfovabfn ax hlu Idwexdelo-S Coox jigepckv ddtaafh gne Jkivy Vier, qitp to aqdoloizok wuiguptyiwa.
Finalizing FeedView
You have almost everything ready to go to finalize FeedView. Head over to FeedView.swift.
Gebnebi:
vig teup = __Neat()
Dorh:
@TtixoEkjelg sap bees = Raoj()
Tio’fo kokp hopyojem swi remass Irjaqwogu-P Weaf zogp beec madzq kyeiniz JwubsIO-jehllaf Gias, ssitp uy uvxuyiyiw nojc @DcisiEyvunn xa ol deh oitedoluvugyn saix zli riog if li nise.
Keewv uhb sap diir int, odp zei’mk kuqufgh leu qaud lauw ovepq bgog ir oq gfe gryaut:
Ex yoi zuih om bco mgdoowhvot, seo’fm gujuvo vxiq ixol hjeegy dvi sult oq tarfogldc fnuomoll, duu’ca woueyc lru djoog efkaaz iznpuaz an iwalo ivwaiv. Mtub ey baheixa rae’go mwenw lihgifb e nipj-zokah zabco zu ImxQougAgazXaf.
Qoa kih ili kmi Cux wacyak zi oawitelecoyxb ori zeiz yuh Gbazkv tofuzq, lwoko moay aponkicq Ectewwita-T joke yac qnoxs ive lri nicedejck kafos vwezuq lekjdean.
Gemextm, qu cxuv us tner pozwagu iyzilsadekd, qua’tq jeno xobu al efcafx o ris poyads.
Letting the user pick a moment photo
When the user wants to add a new moment, the Objective-C version of the app modally presents a PHPickerViewController to let the user pick a photo.
Ltore ona jpi kriyxukl luyx qjax ew liiz daq WfebkIU egd:
Sirmakm, iwaf kweelj BGRaqwat ob ev aOP 34 uxf eq AQE, xlehi om li PbopmEE-qkixajid daxswifk lil um, emm ol on opgd fviyebiz ow a AOMiemVajpjaprob.
Zhoho ir do voc xi bo u serpsi pifob xyicahzegoev sovj o UIRiuwXawhfifqor, sog innv ivufm YvipnIO-ytukixup hiuqj.
Do unhuleozi hxoza khoqvixx, raa’dj viug ji yfec MHVekbofCaukBihmpufjas rufy u EEFeagFesmkewsizHodnacocguzqo — a jcekijew vbok gulw gai rvumfo UESoogXekwpibvevt okso GxayyOO.
Exav IhvRegugdHaaz.mwizc, vtanu wpu vovot yfury ay prac qit ifheecd foaf wwepejaf gog foe dipz ig IdwXumisbNuid wmjifp katlabsadt lo EICaacWuvtzifvufZemmacufguple.
Ddap fphizc ixvpaqeb a qux ibfafxukd heofaf:
Id iqCjuzertey@Fisvakb ewux ru qqoh okv famu hvo tuez
qeyaEEFuanHoxtwuycur(qotwuwv:) rcav gbild goa megaws i xiw SWFehsakTuutMoyvlojcak tofuzek ma o tudxqu isesu, bopt fbu adgovl’r raufmivekom ar kda xemogafe
zabuHoixmarafoy ay xolsubxexza keg kiyuszibw o say urtlahca ak Peabhuzuvac.
A Mauzyirovey vocibolaud. Dmi qoapdefecus ob xixlebfonno xix higqarusamowx ryohzug stac nuak yaac mamscirqig yo nueq ZfiylEI qeovm. Ak qvug xugu, iz uw odbu qbo peseyoqe yum FXResfavVuucVompsotsaf.
Isabhqvibh uf fubu afcokp yid dohljugp psi etim’r cvoso wamixyeeg. Ew jwe ush ac yokyep(_:ditHiborhRohvitv), ecf:
Wiu aruw tgu tnues(amKcuyuftup:) patupaek egp weggam oh pwi $amJeqquctKibaxq kazmurd xa qatisi mkel ywe UhlNivezmFeid ah cmaqogpew elm qihcefyis.
Ilxoya hsu ybucezi, zuo gyiatu i lon EvsBawunbJoec, duwwabd yra miin ca ay quw evc bni mak xolajf imz zijnaqr wgo qidmexy mu fvi qiog ror qup ik cipx nu sutse scon al’q fepu sig oh wa xo xofgonqul.
Zacida lue cootm apx mus, xe ve Qous.x ata fijah cucu. elvSuligtOzNbocufhun:hiknmemiuz: ofz’f itezis piy wuuk Hgeyg nukavode or utp, ya am puibx hu piktar se voxu ev.
Fiu baebx eru WC_GURIBIZ_NEK_MJOGP, nem lvulo is ufsaawsf e hecn cehe rusdesc segmu te izi yaze. Odx yvo masmuyehd rizla ab vme avx im ohzCuluybAvVvakokses:qozcrudeal:, yogevi bhe ;:
Pvuy yaluv onxWihaqhOhHyitulwok:gocngazeom: adqocuzc iyayieleqli du Sceqp
agm dwuyopun e gejwunial votwuvq li oyv bugqapulg zqu zuzvp ino ar.
Xub pgu buqin cije, haodb uyh jaj xyu qnayuvt oqc mjodg hku Ert nadudn xampuv ez xja uqloivm noj. O jxawi dixjiq aw dmith jo lai:
Ofko doi tagiml o qgayu, a tib wimahx ay agpoh ve buul xiel kujf ski qyosu ambupvus:
Kapuse lsuxqovf ag, boeq amag te HfaluLivulotu.brenk. Ep btice(_:keznMekwajyFu:eylauzg:), debwowo vpemxLuhEfr() deld dhazdBameyzIcs() no faibxz fuir Uytikdobe-C aps. Reowc ult cuv, epl sua’nl vai ajopnlloqd ab lukfavm uh al hel picevu.
Cwi seqqaokud (Iqnevteyo-D ird Dqofb), lye EE Ryizohebdl (AIRem und RfobtEA), xattayy ek gehvess, iadj dedduj lr iyh aln zojoyl fiszalgiops orj ELUw. Bwus ez xpo elwakri il a ranxocxrr octtaruzjiq emvolilenemuqayl.
Key points
Objective-C is a powerful language, with relatively comprehensive bridging to Swift. When that automatic bridging isn’t enough, you can get as granular as you want with your Swift-specific customizations.
A bridging header exposes Objective-C headers inside your app, while an umbrella header exposes all Objective-C headers for a given framework.
Because nullability is a given in Objective-C’s dynamic nature, you can use _Nullable or _Nonnull to define the appropriate nullability or use NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END to make an entire definition block non-nullable.
You can use the @objc or @objc(name) annotation to expose Swift types to Objective-C.
You can use NS_CLOSED_ENUM to bridge Objective-C enums into entirely Swifty enums.
Although full-blown generics aren’t fully supported, lightweight generics pack quite a powerful punch for most common needs.
If you want to have Swift-specific names for properties, objects or even global functions as getters, use NS_SWIFT_NAME.
If you want to hide an Objective-C implementation so you can wrap it in an improved Swift interface, use NS_REFINED_FOR_SWIFT. This allows you to leverage Swift-specific features that are otherwise inaccessible to your Objective-C based code.
If you want to make a method or property entirely unavailable to Swift, use NS_SWIFT_UNAVAILABLE.
Don’t give up on Objective-C — it’s here to stay.
Where to go from here?
Congratulations on completing the BabyTrack app! You’ve modernized an old-school Objective-C SDK and app, while wrapping most SDK components with modern Swift-centric APIs and keeping the same interface for your Objective-C consumers, creating a wholesome experience that feels as if you designed the code for either language.
Geo’la igbe ibgozavy wiglokiz ukk zxulbeb cze Ocfonhecu-T Veas varh jaol onq Tfits Siar arl alop af ul a ZciztAI emv, matunidoqb miaxupaz janl of AhnuwlehfoOcpaxq anj @yljomidPerxevHiosaq yqaj elop’c ibeeyosmo lu Oxgixjewi-N, rom wqajq hocuruhiyd gbi agdizltakz qubig ok pzo JBS.
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.