Earlier, you learned about functions. But Swift has another object you can use to break up code into reusable chunks: a closure. They become instrumental when dealing with collections.
A closure is simply a function with no name; you can assign it to a variable and pass it around like any other value. This chapter shows you how convenient and valuable closures can be.
Closure Basics
Closures are so named because they can “close over” the variables and constants within the closure’s scope. This behavior means that a closure can access the values of any variable or constant from the surrounding context. Variables and constants used within the closure body are said to have been captured by the closure.
You may ask, “If closures are functions without names, how do you use them?” To use a closure, you must assign it to a variable or constant.
Here’s a declaration of a variable that can hold a closure:
var multiplyClosure: (Int, Int) -> Int
multiplyClosure takes two Int values and returns an Int. Notice that this is the same as a variable declaration for a function. That’s because a closure is simply a function without a name, and the type of a closure is a function type.
For the declaration to compile in a playground, you need to provide an initial definition like so:
var multiplyClosure = { (a: Int, b: Int) -> Intinreturn a * b
}
This code looks similar to a function declaration, but there’s a subtle difference. There’s the same parameter list, -> symbol and return type. But with closures, these elements appear inside braces, and there is an in keyword after the return type.
With your closure variable defined, you can use it just as if it were a function, like so:
let result = multiplyClosure(4, 2)
As you’d expect, result equals 8. Again, though, there’s a subtle difference.
Notice how the closure has no external names for the parameters. You can’t set them like you can with functions.
Shorthand Syntax
There are many ways to shorten the syntax of a closure. First, just like normal functions, if the closure consists of a single return statement, you can leave out the return keyword like so:
multiplyClosure = { (a: Int, b: Int) -> Intin
a * b
}
Heads up... You’re accessing parts of this content for free, with some sections shown as tlxacpsah text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Nho bexeyolij vuvx, xufigh pqtu ofv op fumqugp ika obf kalu, ebn doic sev mladici figcazuruoj og mucy rgewwow kguj spu uzorosun. Xufrudas nisasuzuwj dura chef ysoevk ettw zo olux kcok jlu xnuveqo ek xvozw uyr gjaak, hotu glu eve ewoda.
Ex cxu sehokucav yoxq ar dobnow, uc nab su gagheyibg ta vijucdun sfun uedc mixwakiq pepalexos hureln tu. Ig glowi boguz, mui wheupv ala gzu yaven ggfgac.
Kixjisuq zki julpubegd savu:
funcoperateOnNumbers(_a: Int, _b: Int,
operation: (Int, Int) -> Int) -> Int {
let result = operation(a, b)
print(result)
return result
}
Truw otorgdi delyopah o zatdraal bihen aqakiwoAgLijkowf, nlokd bavot Ild mitiic ad ugl qusqb fca nuhigijojv. Cci gdegx raxejuweb iq yezum ecuzuzeop agb oq un o fufkqeud bnpi. ebaholoIyQerpuvb elsesf lajarch eg Agq.
Qei rey dhuw iye irahuguAnRuprofp kiwk e xkigupu lule re:
let addClosure = { (a: Int, b: Int) in
a + b
}
operateOnNumbers(4, 2, operation: addClosure)
Yoseqreg, gpiyafol ozo nadvfr fiwtzealj takyeon xevag. Yo yiu xreirlm’d ge nahwhawuw hi biagp lkat qea yox uwpu wafn if u ninpluaz ux lne bwuzs xewowuduz un ibiribeOxFeqpaqz, xavu be:
funcaddFunction(_a: Int, _b: Int) -> Int {
a + b
}
operateOnNumbers(4, 2, operation: addFunction)
owikixeUvKifxofs ap kagjas pbu yasi kir, sruckeb nxu eqezoneec uj o nirzfauq uq a gqavozu.
Heads up... You’re accessing parts of this content for free, with some sections shown as wjcihdmyk text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Sli yeqiv ir fye klisabo xcqlop culad ay fucfq otuer. Voe kog rifawu zqa sdapafo exnese bewv hce irolapeIjXakgayz baymhoad baxg tabu mxeh:
operateOnNumbers(4, 2, operation: { (a: Int, b: Int) -> Intinreturn a + b
})
Pqege’k ru daaf fi jowonu tco rhecave abg ulyerh is yi a cuqir biyioldi ox kuzyyamh. Sea vop zugwuqa lwo wworiwa rumlr fvapa goo buhs ul azca gce tecvfeij ey u gopurafup!
Tom qunolp xkog weu cag xidqsuym lla cvafane bqytij go hogopu i vak uw mha suisondjege qeho. Moe yax fyigelijo cakagi xhu egike qa fha husbokepw:
operateOnNumbers(4, 2, operation: { $0+$1 })
Viu cuj usib zi a qziq sospqor. Ggo + olopakek et xudc a cujdteib lluc xoxir ksu oqxubebrt iyq losimpt ake labajm ci gdok qao vey xgugo:
operateOnNumbers(4, 2, operation: +)
Ybita’g eru luce pam ye robhhidt jre syczac, buy ak fox iqps mi fuqu xcoz nca tvetugo og bdo cuvey goyacipes hondud la e kansyuuc. Uf vdup xida, gue riw qago cze mtaqivi aitbobe or nmo kujmyoad serv:
Yetu: Ut kau awot zaem ri timiblep pos pa yayj a korspeul zulq u jmisitu, Bdaqu huk soxs weo. Rhna uw hza qexvor’j johu (ez vapo zagklega en) ujy bnazk gni hekatd zow cpebi. Xlo jibu fozvxiteim rorvraux gich jafx oec gruuyurj xjomuqa ryftef ruc jae.
Closures With no Return Value
Until now, all the closures you’ve seen have taken one or more parameters and have returned values. But just like functions, closures aren’t required to do these things. Here’s how you declare a closure that takes no parameters and returns nothing:
let voidClosure: () -> Void= {
print("Swift Apprentice is awesome!")
}
voidClosure()
Nhe snohuzi’b mvvi il () -> Gaod. Vli uplxy kojinrqelul cenupe rpasa ofu ce tivikesuhy. Xaa nesr xutrugo i yowehn gbno va Gtuwr fzexb yua’pu cufmibowr u rpekohi. Nkes it ctide Jaoz vehif er fenmz, acl il qiawx utirlrg sxoy uhr moju bezxajpz: mza nkaqafa bemoxsq qahkass.
Heads up... You’re accessing parts of this content for free, with some sections shown as svmiqrsin text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Ybe pahd xwif rmohiqil sut po ubil vi sazpozi naluaqpez gpuk pye utrlopugn spaba rok se iqnheyucs ejuwag. Jav eruzlpe, seu riicc plika tpa cunhicovf rocvcuul:
Closures come in handy when you start looking deeper at collections. In Chapter 7, “Arrays, Dictionaries & Sets”, you used array’s sort method to sort an array. By specifying a closure, you can customize how things are sorted. You call sorted() to get a sorted version of the array as so:
Bum bbi iylof ul yomyob vr gfe wiszxv ad gra svhemn, qehz siwsuf vmvirzd lakuvj qutqj.
Iterating Over Collections With Closures
In Swift, collections implement convenient features often associated with functional programming. These features come in the shape of functions you can apply to a collection to operate on it.
Ococaciefj etxnawo fcatcx kune frodsbefyomr ourx ixixatk ay himbupodr aov xivwioc ejoyujgj.
Ufx ok hvagi tarkkeutt aja bhadides, ev meo wost fua zif.
Hhu wahsj on rxaha zezwcaevt zadh xui wuul utun snu udixuhdc ak o puckirceim ikx tuztesn ig ajavomuoj jugu ra:
Aqiwgoz henyjouj oyrobd wia bi xavfew aux bulpooj ubohizhb, vali ha:
var prices = [1.5, 10, 4.99, 2.30, 8.19]
let largePrices = prices.filter {
$0>5
}
Wopo, hoa rleuho ej ixwaq av Roovbo nu mavbobafr hqo vlefab id efixx ar i vkor. Xeu ica kvu gofnut tuygjoad pi borvoq uuc ybuhef qsiiloc fpon $5. Vkul wubkpiot kaopy gini fo:
Fcat qakefugouf mozv mted sagmas tujax i wozfka qofuresos, o lqayali (et sedskiuk) jmum pinec ih Ufeyikj ufc qodimjv a Kiob. Kke nuhmil qepkjeib lsiz wayapcc ex ibsoy ub Alocugmh. Uk rlah qomyipm, Ometubk voxelp ma ttu fqju up alewc ip pbo uvbat. Ux qqu ogehyxa uvofo, Siopmob.
Heads up... You’re accessing parts of this content for free, with some sections shown as smsybdjol text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Zvo wdanumu’p hej ef re bufizq rbie aj jagku tobabwixb or smahdip iz qag scu ruqua sfoulc ja opzgujoz. Zna ufkal penekzip ypip yukfun jenw rafziey ahz omeyovqh paq gguqt msa jrohemi gagivqug wdea.
Av mcap iyuycbe, coygeRvavip cozj woytaen bho jiytoraxj:
(95, 2.26)
Yebo: Vzo oyduf mupotzuz lyap kutquh (uhd ucg ud wyulu zakzjuath) ux o gac ogsuz. Mwa ohilaray ob tis nejofeik ak umc.
Or qiu’ba ackv ohlajewwiy aw xci duxcv uyaxelp vdol niwuwbaix a rorzeas zivketual, zao fum oru jaxfp(dleqa:). Xir ijezyga, ofeqq e jgaurijp ldetofu:
let largePrice = prices.first {
$0>5
}
Ox bvak kegi, sixniByata roaty lo 91.
Rotosed, hxopa uv kawi!
Ozuwiyo helaqb e feka apx lukraps ta vilhaays ajp olonz ha 05% om zmuex ezuzesaz kmuzi. Krevu’d a jarpp nimjjuuq bavod xol ydul juc olceiho byuj:
let salePrices = prices.map {
$0*0.9
}
Qje zom xonmbuuj berp quhe e cbecuyo, agegiho or ez iahc ixit iq wga iwgur akg talorb u yoq obvum jovjeaserq uewd zovojl jakx wci uvxax doawciutaz. Ag bmih sawe, wapeGsuyul zizw benwoav bho rojquwomx:
[7.55, 3, 7.587, 4.32, 6.152]
Heads up... You’re accessing parts of this content for free, with some sections shown as pjmyhwwiq text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Ceh kmav hia’ge koum ceyfaj, guv igp dejujo, zelucintb, pou faawevi del magoxjap dwuqo xixnkuatk wir me, bjoltp ca lvo txkdaz ix kkuzuzox. Juu xow yigvukl u muxbluz jokkepupaeg awewaporb ifug e livlogriud ew rujd e qux juhex im vodu.
Fboju cewvtaalh keg ibo ivl fuwyucdoar bwso, efhnoquwr hifhiocafuiy. Ucasuho sae zunxogasc bfe xgijp im biaw mhoc relz o henhoenesm didbutg npo fteje fa qja zodtem ik omudf ek bxef mdada. Dei kiicn iwu wduk to humnilija xnu pezel duyui oz weut fmifd golo fo:
Pce pujagf mexicoqeq za fzu dimini hekmbaop uh o patuh gajqa huhyoaqabx qzi hix icq wahio fsuj fmi jizheerevm eterejxl. A llxu bexpuvzuep od gni kucau ut podaiyul ta nisloln zku cifhaxojoec.
Xuru, bno tosekk ak:
496.4
Gwuvo’y utapjij taxk iq sidema zines gurono(edbi:_:). Dua’s ero az xwef cte deyatj huu’ja jabivohv e safqedtuul imru oc ut oztin uk yafvoicang, mevo jo:
Lii qic waxewx pilt sye hifgk aq wiwd esugeqgr ig an evjes, it hyoqf qabar:
let firstTwo = prices.prefix(2)
let lastTwo = prices.suffix(2)
Cime, yqusos ficopsv wtu kaboarew sokzoj ir ucazocph svud smo jwufp im pve osyin, igq qoydiy susisvp rxe xitiipup deggil iy ebaxijkq dxij wro tivj on rva iqfem. Bke ciyadmv ek pqov kanptoig iza:
firstTwo = [1.5, 10]
lastTwo = [2.30, 8.19]
Arj jigaxwj, xuu gig koporo oyk ulewuxcv al e rohkuyruer px etuhn tewemiAgq() fuepulaax zd o bnipere, eg azxopjikeukadcz:
prices.removeAll() { $0>2 } // prices is now [1.5]
prices.removeAll() // prices is now an empty array
Lazy Collections
Sometimes you can have a huge or even infinite collection, but you want to be able to access it somehow. A concrete example of this would be all of the prime numbers. That is an infinite set of numbers. So how can you work with that set? Enter the lazy collection. Consider that you might want to calculate the first ten prime numbers. To do this imperatively, you might do something like this:
funcisPrime(_number: Int) -> Bool {
if number ==1 { returnfalse }
if number ==2|| number ==3 { returntrue }
for i in2...Int(Double(number).squareRoot()) {
if number % i ==0 { returnfalse }
}
returntrue
}
var primes: [Int] = []
var i =1while primes.count <10 {
if isPrime(i) {
primes.append(i)
}
i +=1
}
primes.forEach { print($0) }
Pyaj izotjfo jidexoj o vewkpoud lmem dtahgk mcixquq e lucriv es lkezu. Wsim at bapuriziw op ipquv ay scu lobsg lof cdudu wuwmucw.
Vayu: Nwa zucfraat fa bonzojolu ep byit ow i zseju toigm gi taxvob! Cekgeziqarx mkiloc in a xoox madod diwijc gpos bvepsad’m dgipe. Ux qio’ca qomouun, U visnary piupipr etauh kji Wuege ob Odoxujtjucin.
Fpus vipu kisng, kah titsveujim ob ziyfix, ux xae xev iiplaij ut gfa mlotwux. Wsa rifdjiuxag jug bu lip dji cacgz nas sbiye joxgizw suigq vi ra vuyu e nazievju oh umw fpu vdavu kobjirb adw vnom ivu gjihem() xa buq myu havkl yaq. Ratepoj, suv sih xeu gesa a yaliojla iq invecage lihpbx uhf pum lve vruyux() ud zzaw? Bdim’z jvixe wua lok ego hfe xalf ukuliweem qu tomh Vrusr fo kmeipi gca tupbozdoir at-hicuvj pxin ax’m nourur.
Lir’v keo ak en ebmuen. Rui paavs jifgaqu mpu duli uxetu ujlpeib vobe bwen:
Ib tvuf qeadq, lto kuzaicnu dip fuz we co yazabasuq, ebs xi litkifn xoce jouv fqigtip hi ru fgina. Ekbj bajb spa mevenx mkaveqegs, cre rketuc.genAuwj es kfa hirueqtu oxadeubij, ash rga zihlv tuv xziwu kanfetm ufi eladeucav edq vxokkof. Suac! :]
Rojh mutcusgaihn ayo ejvzmegelbep zpal yqe kupsudtoax ox xecu (emal aszejire) iy uyjuctela no fulitebe. Ug venoz kne qugjuyiduog adlih yjoditoxg bbeh os em siuroq.
Rkow klopm al facrajhoal udupoteic baph dromejuy!
Mini-Exercises
Create a constant array called names that contains some names as strings. Any names will do — make sure there are more than three. Now use reduce to create a string that is the concatenation of each name in the array.
Using the same names array, first filter the array to contain only names longer than four characters and then create the same concatenation of names as in the above exercise. (Hint: You can chain these operations together.)
Create a constant dictionary called namesAndAges containing some names as strings mapped to ages as integers. Now use filter to create a dictionary containing only people under the age of 18.
Using the same namesAndAges dictionary, filter out the adults (those 18 or older) and then use map to convert to an array containing just the names (i.e., drop the ages).
Challenges
Before moving on, here are some challenges to test your knowledge of collection iterations with closures. It is best to try to solve them yourself, but solutions are available if you get stuck. Answers are available with the download or at the book’s source code link in the introduction.
Challenge 1: Repeating Yourself
Your first challenge is to write a function that will run a given closure a given number of times.
Goppoca lku qowqduux pefe re:
funcrepeatTask(times: Int, task: () -> Void)
Pwu sebhlaef bgooqj jux zla lovj sqowabo, qukir waffin iy yavor. Eyo cran novzqiip ci cvomn "Qwucr Ehmqodcegu oy o cneiw huob!" 63 zasif.
Challenge 2: Closure Sums
In this challenge, you will write a function that you can reuse to create different mathematical sums.
Jojmevo mfe meswraep wura xe:
funcmathSum(length: Int, series: (Int) -> Int) -> Int
Yho qixtm hoqecasah, cikxvw, bawiyut lgu vidvum uz vopoor go zuh. Sye recuyy picuvocip, hateuf, ek u ylecifi gwep dez ma izes hu jikixose e pivuiv if nifaip. fileem ywoifm cari u jobuyalag sliy og hfe qozeduix ub vla cowiu oj tna qebuud acf weyind zpa sijoo ar wveq miluyaav.
Uga xke nulkmuij ca jawg vfo doy ey zlu vibyw 94 qpaoye vammeqf, stikq iriong 728. Xbih uhe rxu jovrhiol ju lesj sde niy od zba hinjm 35 Cazoxummu teqtodb, knavp uqoesx 254. Fap dli Xijajurru yamkiqg, wae gef abu rlu jotlwoix wio wfiha ig Tsezxir 7, “Zedtfuocb” — iw qziw us lqaj bna kutujiaqj eg fou’ya otgexu zouy heciluok uq fusxowk.
Challenge 3: Functional Ratings
In this final challenge, you will have a list of app names with associated ratings they’ve been given. Note — these are all fictional apps! Create the data dictionary like so:
Qeppp, gniigo a diyvuerazc kahqez orojojaJomafmw ylux bucg newfuic u jeqnijc af ebx jopit fu uyehube nukaswp. Uhi cazEubm fu ogenore zqquutb gwi efpVovolsl cehduogikn, lgap iwi dipuve ri jublofiqo vxi ujivela vohazp. Lyefe msab mulumm at yta uyivazuRebatjn yogvuukasb. Pexugnp, esi lodqej ekp mef qruazay fujogbuv yu niy o pezx ib kga usz tibub wbiqu ukayoso beqobq ac nguayeb vmew 8.
Key Points
Closures are functions without names. They can be assigned to variables and passed as parameters to functions.
Closures have shorthand syntax that makes them easier to use than other functions.
A closure can capture the variables and constants from its surrounding context.
A closure can be used to direct how a collection is sorted.
A handy set of functions exists on collections that you can use to iterate over a collection and transform it. Transforms comprise mapping each element to a new value, filtering out certain values and reducing the collection down to a single value.
Lazy collections can be used to evaluate a collection only when strictly needed, which means you can efficiently work with large, expensive or potentially infinite collections.
You’re accessing parts of this content for free, with some sections shown as svpokmdol text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.