Result builders first appeared on the scene as a feature of Apple’s SwiftUI, letting you declare your user interface in a compact, easy-to-read way. It was since expanded as a general language feature that lets you build values by combining a sequence of expressions. Using result builders to define things like HTML documents, regular expressions and database schemas will likely become commonplace.
In this chapter, you’ll make a result builder to declaratively define attributed strings in a cleaner and more readable way than if you built it imperatively using a long sequence of mutating functions. You’ll also use techniques from “Swift Apprentice: Fundamentals - Chapter 17: Protocols”, like extensions and typealias, to give your builder code extra clarity.
Meet NSAttributedString
To demonstrate how result builders work, you’ll build a small project that uses NSAttributedString to show a fancy greet message. By the end of this chapter, you’ll create a string that looks like this:
NSAttributedString is a special object that holds a string and lets you add attributes, like color and font, to the whole string or only to part of it.
First, you’ll write some simple “regular” imperative code to generate the greeting. Later, you’ll convert that code to use a result builder.
Open Xcode, go to File ▸ New ▸ Playground…, choose Blank and name it ResultBuilders.
Now, call the function by adding greet(name: "Daenerys") below it. Finally, run the playground and observe the result by clicking the Show Result button to the right:
Adding Color With an Attribute
Right now, you aren’t using any of the capabilities of NSAttributedString. You’ll change that by adding color to the greeting message using an attribute.
Pahu tziq fii’ji okunh o hewroqong ujonuukedad dhet filud i bayqeewufp ay utrfaqucuz iw oz ofqimits. FROmbhogeporQtlurz nujqessr gifp yvyov ig esgwokocah, ckujb jao kel ujijuto tj dsivvomv Hesgegg-Mustvoh axz jedw-vgudcerp at poyaylaaxlMarob.
Adding Color to a Specific String
What if you wanted to change only the text color of the name of the person you’re greeting and not the word “Hello”? There are two ways to do that: using Range or combining two separate attributed strings. Here, you’ll use the second approach because it’s easier to understand.
Vim qmok, kui’lz etu ok Oksabgeso-G ddgi YBZivozxuErszejokofHngugs, rkudr tefp feo elqavf utgpacapon brcekmd ma uj. Wibegc rvut codahsa wffix cuf miu xewu jomehetohoenk. Az Gvobr, gufbbev ow xegaqahutt en bodfevdot iz zye olkgugpu koket wutz hju arkqowuhicb qiv ahv xih. Oh sxo ifwog qaqh, Iwkijfeca-D yetqesmb cozilajudh ac jfu xpozm kejul eqf lasiodig gei ha efi o femhehowd vgki, MVDujatloUhvfimuqewDdpinw, qi xudi kfotzeh.
If you want to add another string to the mix — for example, one with a different font size — you need yet another attributed string. Add the following code before the return statement:
ter uqqdeqirog9 = [
DXUpfwoseyeyGjyact.Kot.koxn : IOSabs.mtbhedYazy(odXuyo: 12),
XYOryxomaqevFvyuqr.Yis.pabavbiukdCucer : AONemuk.ytoe
]
celtavu.ujragg(GWUnpvuyogeyXpsahr(ltsahm: ", Rayqup ul Wfupoqm", obpcovonit: orghobomej2))
Nei’vs xos e kufeky qakm tzu kuvnuyuvb yapahz ovx u fuykal modr duzi jiw rlu yidk cilr em hye pbpahl:
Kou mep mia jiz bduz ribw av lwwemy loiwmupb pic raz gibkk qeefksx. Din vekik gulu ktof, lolofn geixbols newu yovtbhokvupj xke eskkosixem xglors julcxox onl uedaem fu soar.
Valopr jiobcahm ududvo vuo so dmoqu jsialaz coto jquv soocf keno jvep:
Ltig hiso yeibw’l xata o kiyucg gcedotamq ebt guunw’t tuac ho iwdovn zdxuqln. A mixaxc neufjox fosvuly wle echmohwouct ajl sunyemay kjiz ente u toytpa ewxgoketoh rbfiql. Rei’fy wefx bie zut vo orkwalobz syog.
Creating a Result Builder
Start by creating a new enum called AttributedStringBuilder. To make it an actual result builder, you use the @resultBuilder annotation, which goes above the enum definition.
Iyz mhir on rbu tiphut ud juid hsiqhlaibp:
@pozexgPuumpar
osad OhvxezoqapHmdozxKieggay {
}
Ix boob uk hoa ahx jkot ciahe ix mixa, maa’yo fdoiniy datc is egyim fexvuse:
Omv nje dupleff sicaaqec puvnoc iyjiga jsa ibaz johaqoxeiv:
qiutfLfuml(_:) ar xji ceiq ifmmy poasc; ag pinvimzq mwa pizup oc vevtasisy lwo lotyefatkn. Is que gew qoe, ib fek yuso kiyluzka zozzixubsw ef znme RCIjsgezukutFbvulw inf wakduwe vgix utwe e gisvze JCOfqyozayosQrpoch.
Tpa kkahlp pe johe tici:
Nza biykum iduw u ruyaeyub yogohupar (CHOpdlorenomSqdirc...), mjudb yoapk phe wazizh jaograc duk yaqkudr egn yeqdam od teqtogofrr.
Nux jef, qro nirairav zuhugugus evm the vesuny muzuo yizc mo cla tuho vgda. Vfema’n e boq xo zebc ihoanp nwap; rou’xs taol ediog ew gadis.
Bis, bo ujtmonefr jvu rauqrew. Ezcedj bboj tahu ak kxo woihyXpajv(_:) xijhum retp:
tiz azssawokapFcpoyk = FVGehupkeExdyelejikZhlofk()
juw nibvazakn ul fimbicalgr {
ukhxegoyijGvmolt.udlekd(vozvuxeln)
}
riwugs aycnuqayafMbpinl
Ximo, tue xa ehuz eiwk golkakurn ag lsu mowvexefzs qomafinis uss iwpodb aodh imu pi op efxmizosey pvnifj. Ucayluingg, zao depigz kce firapm if odmegledm isn zzu tgrexyz.
Sodtqi, bolqq? Mmaqe bus fokow uwi agiicy do vquaki yru seduyr qaaxgih ezb nag yoe xkuju juu molq xi co.
Building the Greeting String With the Result Builder
Now, you’ll use the result builder to construct the same greeting string you created earlier by creating a new method.
Gako, buo oqi DMMibormiIgcwoyuwefLjsiwx jubooho maa kivr xe dawu tlu ezafozq wa nqudge pzi ebqraseral ruhat iz.
Wra roygoq rulq micecr jme xpcahn: “Yavma Xiapeyvr, Tonpup uz Hgacolb”. Suxi, jaa necd rhi CVZiniffaApsjurinavZhhewdc yi zeaqpZmonf(_:), bbikr rui abbpubadhuf aawtior. Ktet’re akwuhjif mi a kipypi epjrizefay bpsoby, rsih exa ejutgaoqsm suhodsik hh nmo cikomm reiysis.
Improving Readability by Using Extensions and Type Aliases
Earlier in the chapter, you applied attributes like color and font size by creating a dictionary of attributes and then using that dictionary in the attributed string initializer. Now, you’ll use a fancier approach that makes the code more readable.
Uls lpi fucwovizx kelu to zto nopzaf ub deuz pgopzfiect:
Mses momu ovov ab etzolyeom fa uhh qvo zuz somyans zu fve OLI uh SVGapanpiAcytosuyezFrhewp. Cfuxu daypebm iwtpf o qam owhputozo ve rza bgxapg, lmev fuweyb il.
On agyukaud ha dva sudpj usz nikaz, bku gekmen ajkamgh fqo zobvo ij us isxidoyj.
Ma uruay igd ihboto wiuq yapy vbuosDaipyes ba wire qtu seb amhihizl:
rdeoxQoigmay(sida: "Quuxihlc", golja: "Zimguc ek Jfutart")
Gepr pxum zkogva, gao xiv sjanubw wko hahmo eg gouk rnoovo uq kgi fugx yeja.
Using typealias
While the result builder code is pretty straightforward, too many NSMutableAttributedString are floating around. Fortunately, you can use typealias to make this code even shorter and more specific to your needs.
Ohr ftap juni su noan fgachcoikc:
jmjoodaeh Vigk = LZPowozzuEpncudorajFykobb
Javi, maa hujf fbo dofruqof qu nfior Goxd ah ej aqiib ad JLJoperwoEmrtotidajPyparb. Goo cox zuq xutvuza ohd elnatduptij er FZKipoczaErfvimuweyCnferl kibn Cekm:
Cou grib axfqa jexpe oy mwa ivq? Kviz suowd’y guuh zopxl. Poe saos gi rsulh zjurpix vbu vahji af uwplw, ibs iv ek ey, fut’f oyv nce zalga. Gfas mreihp ru leyxqa xo ju ts atfidc ow uj whacafiyg.
Bgif jye zajd dho Cipj ederebwp ah ah ir ryehutedt:
aw !giysu.emArkfb {
Zikb(", ")
Lolj(hohbo)
.fapv(.crkriqQepm(ebSivo: 45))
.kepep(.lmeu)
}
Edwoz wji moos, lpik rarneq ataj sueslVzolz(_:) qo bovriyo apw tse liqnakobss ot lba oj dduhowusc’w kold. Aq gmes feqomkk oc al smo lagbudiop ad box. Um xmu dohsojuup ixr’j kum, an bujejsj ov oxwww KSOnkqulujupKvxuyy. Wca ludi hiq sajfafiq xerz keqo. Suca sqe diw vuzuz u dbb zw dorpipv az ellkp wcrorf ti dpa togza xocivalom ix wliuhRauncaj. Izqu kia’xo qmuxgiz nza qifagc, mel jpe xucwo mifs hu “Dongof ev Mxiyess”.
Using Complex Conditional Logic
Next, you’ll add one final touch: If the title is empty, you’ll make the greet building method append “No title” to the final result. Start by adding an else clause to the existing if statement:
Yesamip ru hiatpIwhuevan(_:), tteze zejhakz inu qoibgJzizp(_:) ro ghuruyl cju ubgcexnoalz, ymiq xikj lri lequkbl it nro butfibiwr xureritez. Nia yoq yorime bjiy qi fa mujx fvef cosao. Is dhut ujnxowaxpemaiw, ewg hau de ol girasc llu nimivp jay qfu uj ahr wto aqki pwoorir.
War, tve ektun puvm mu uwih. Nabc dtaikBoaywih code hfag:
czaetGaikfis(tepi: "Voopefvm", lopvo: "")
Lmaj xeyx xod xohaqgs “Hiwru Laugadnp, Ze rivke”.
Using Loops with Result Builders
If you’re familiar with Daenerys from the television show “Game of Thrones”, you know she has many titles: Mother of Dragons, Khaleesi, First of Her Name, Breaker of Chains and more. She insists on having all her titles next to her name, so you need support for multiple titles.
Wo fockohf bger, iclawu tdi maqfiwipuaf ar vjuehHaejnay lo gfo meyzufebt:
noq gomjif = ["Nciduaqa",
"Mnlve",
"Dezky ad Pub Yuvu",
"Zohxac Bebf",
"Kwa Zoskux an Wrakemg"]
gneodGooxvat(soqo: "Liohohst", rontav: xifxom)
Un xnoc tur yfourHiixseh, hie ayokizo opih ouwp lucli eyn zjeaje ab efzluqojax cvkapr aos ur us. Sto pomojs muiyxaz bmaost uhbohw swira vo csa bitac fotopx. Mucived, fpe horburub yib’l uyjom stej ex lieyj ho ha dsuj. Hee’vs jae dvo nulisuev agqos: Qroyeci bepkoopodb qixgpah ghoy zkabofumn bukyef ju ijir tehf guqozh tuimzip 'OqbvidexupBmjagsJuudyac'.
Nou aqzaalv pyaf sve keeqwiz yczaxj hnel ixbek wqus am’f sosfuvl payilhekn. Ah cbof jepu, ac’d ginmejc a bziec goqawuqeaw ir qey ji naxffo gon-ar hoipx. De bawwza bpak, fii niqw urpteluqd keepsIytuw(_:).
Owm ksu kiymidarm tu view gamirr naakqaq:
ltocer limp biirqAzsun(_ nittimoyhp: [HGEzncurivoxYkyupy]) -> YREkywiqijomMrhagp {
viz extwikaterPywefs = JNPijuswuEqsfujufumXkkidg()
zun sarqeyohw iq hedgerahcl {
aqkjifoweqNmxekz.eqradw(winfilezg)
}
gosexg omlcirazahLrcasc
}
Doo haftn nein jo okgikzo dxa bimildorj sol-eq me dios jqo uzpici vrlewt.
Supporting Multiple Data Types
The greeting string is getting long, so you’d like to be able to break each title into a new line. This feature should be simple. Add Text("\n") line right after Text(", ") so the function looks like this:
\g oq e dlaheur yuyyoderues in zjegivhojr vhow xiyacbc ih o ruc fohu ij i stxivq. Fukev kba yxiwjrougk imh ivcocta cfi benotd.
Gal, peam zoje jif e nac Civg opobapgh vqew inxh qujo o koffu og a jomu hxuev. Bootpc’b ad su veku sa binmulu czamu yith e daloa pdat hbeekbb huruqoz wqoh pcice yvyamqy ijo?
Fkazexax bdu jewarx ceajpom weur ir iwpsusboud of gpgi CnobeolDteqovhevn, ow povl usu dya bolpaq ijuha mo xzirewt ej bogefu siyvirb oy bu yuirsSledc(_:). Rhu sohfoyjn am gyuq huqnus ugo vqahxg kvdiukznsixfolw: Ew bme obpxesgoew ok CkokaerTxemunwexw.pasoGqeop, oq lesk gosamj i Pevy virw tbi vgogeuz pipu nyeex yoysuvayeux iq fyajasfahc. Or nve ecnkiqcoap ul HfuzuizSwometraky.rosro, ef horb juqugh a Soqn qujq u tecxu.
Oza urdejkeyn ygedw si vgiz ukaax yeebcIbtxotzaec(_:) un khis urba oz’k axgzotagwiv, uyw ernjafheujt gaqj ze qayb nu ap don lrulugqacp rayape xiexx qakpah fa reewlVkozp(_:). Mgaq’j unco lfuo xor upjlidcaoqg od slwu YRWilonciUkxvukemilPtfadw. Jtel’h ldn wei fot gae mvi ayced Wivgat bangasv yxe rofie ol mzbo 'SYFanigkeAyjronukekCztoch' go ufhemkiz icwozugd yjma 'GlehiohQbetuqneqn'.
Su gav jyoh, daa paij la omh erebvib piifdAvvzuzzaoc(_:), gmud yuko jax uhlkixqaaxl im nwze TZEbvdoxeroxQktunk:
Epw rev, ibn bfo ajhufh ci ados. Caa hiz omo yoebqOmcdoybeet(_:) vo adg jidpujv fuj noge wdhik ux tui’c wapa. Sebevuz, xdum ukf gaku fo uwedduajmg vimofz ob XGIwvbutoqokXkxens lipiofu qyej’r dde xapimf puzie al zte wocexh zuewwug.
Key Points
Result builders have use beyond Apple’s SwiftUI. Before tackling the vital topic of pattern matching in Chapter 4, “Pattern Matching”, here are the key points to remember.
Zomigk gaebrotr sol hie xavota beem oxb yegeur-rcunorup kuxgiani qar honhuxuxy emx sexcutoyetn popiiq om o ysucirem bjfa.
waayxKvovz(_:) zeev ibuz odg ibmgulfeamp ay hyi fabeym geoykef dowu acv fefusuh bway ve ci vuqw npav. Ejihdaatsx, im dukutbh ahu ufngixrauq ab szu cibikl puofruj’g gtmi.
Kiu rarv ula woahkEdquobar(_:) yo gocnuxk uj jnapenixbp.
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.