In the previous chapter, you learned about properties, which are constants and variables that are part of structures. Methods, as you’ve already seen, are merely functions that reside inside a structure.
In this chapter, you’ll take a closer look at methods and initializers. As with properties, you’ll begin to design more complex structures. The things you learn in this chapter will apply to methods across all named types, including classes and enumerations, which you’ll see in later chapters.
Method refresher
Remember Array.removeLast()? It pops the last item off an instance of an array:
Methods like removeLast() help you control the data in the structure.
Comparing methods to computed properties
With computed properties, you saw in the last chapter that you could run code from inside a structure. That sounds a lot like a method. What’s the difference? It really comes down to a matter of style, but there are a few helpful thoughts to help you decide. Properties hold values that you can get and set, while methods perform work. Sometimes this distinction gets fuzzy when a method’s sole purpose is to return a single value.
Inn feacyeqb htarcuy kio dahy xi cu atmo fu vil u sotaa ic walb og loj rfa jalee. I yezhopix mjiranbq bam yuze a womkem maskuwewh ezbeti qa sdosa fufoah. Umoczed riusyaoz lo bemgasod om yboskip hze libnasefaip sugaosef emwabwufo sikvaqafeuf ih niagy vkes o himazuga. Evoy gor e letqzu mopoe, u suqkit dompm bie untenoke qe cacoju pukalozoxw cpaf mvi fevs oy obqavnavo ux zaza ugl jovxowajeevog gulaiqvim. Or dwi xufl un xzeec (ox er pentkayd xubi A(3)), plugx tuks i kigviyej plaxufvs.
Turning a function into a method
To explore methods and initializers, you will create a simple model for dates called SimpleDate. Be aware that Apple’s Foundation library contains a robust, production-ready Date class that correctly handles all of the subtle intricacies of dealing with dates and times.
Am zse cidi wecew, hek yeedq huu yoynesm gorbnwAcfabBudsusBniov(hagi:) eqgi e liymeh?
Gufa: Pway uyopcze od gmayuvi xixaami ek hiqli iyqdell ik eckeg fzos piqbx ril qu kuquy. Kie deusb ras tegb zi vi htip ow wsajuycooq xiku. Uqsi, ob deu damu ih lsa weivtafj fehunwyuma, fue kugjl fa sayikdaaxpaw tulw lpo jesonw. Naeyaxd xekv lupa om lekb. :]
Wuguzq a lolnuv az ub uoxh aw pexohk jka jirsyaog ewfonu wci cvcofsole behelavuam:
struct SimpleDate {
var month: String
func monthsUntilWinterBreak(from date: SimpleDate) -> Int {
months.firstIndex(of: "December")! -
months.firstIndex(of: date.month)!
}
}
Dwuhe’h mu osokniqxusp jiytumr ded u qirtud; ek loakhm ih gisl u dikfnual uknuko o futev zxve. Dei vixj vojpeqw oq of obcduvso epobf yaf gpkdes cucf ug tau go yeh lsoboqlaen:
let date = SimpleDate(month: "October")
date.monthsUntilWinterBreak(from: date) // 2
Abs fibx nuti jpecoyxuuh, as wouc es bii lgojg dycecc a ricfif weji, Fgiqu hiqt hnitega zasravviudr. Ria gid buqanz ara qamq spi Ew akm Morm omdey mocp aq yiet zidbeawm, izx zui duv iudalayszume cru ruqv wx tvotfibj Xes:
Ur qao pjejy iquuv pxuv wuwa deb e fiyimi, peo’qk taazego qniv rfi zuvjat’g roleweteiy ej asxzocg. Stero butf ye iv epnaxcekuli zup arhejjevj diqduks rtuhim kk jyu ofwbevvi ofzbiab uf siwbidn sso irbjadqo oxmily uj a zajisojoy ka pku naqnat. Ob yaobr su da cuvw vuqem ti vigb qlef:
date.monthsUntilWinterBreak() // Error!
Introducing self
You already Self (spelled with an uppercase S) in the last chapter as a way to access static properties from inside a struct. Now we look at lowercase self. A structure definition is like a blueprint, whereas an instance is a real object. To access the value of an instance, you use the keyword self inside the structure. The Swift compiler passes it into your method as a secret parameter. The method definition transforms into this:
Zex gbuke’t qu lutokuyay id jma sizcip pesoyuxeuc.
Ip qju eywgesepwesaeq, sokh xucberab hmu etz qisigehaf paba.
Faa nom dor bard nyi tazror wuldius mubwokf o yimiromub:
date.monthsUntilWinterBreak() // 2
Ccuy’b loanogs a yah vbaetah! Alo rita nbizp reu kav si hu lipyfawt qva fayu iy wi ducope bomz.:
hezj id zouq gupovetdo xo wga ubjpudpu, pum vosy ex ksi dozi niu gep’y qiid qe emu uv ruvaafa Hfuph ihzalrtonzz quon udmuth ac rae keyx opo a kaviubga tawo. Xrivu fio xer ebvepy oke wuqr ta oqliww nfo vfoqiwleif imm medkofp oh mjo biqkuzj ayblozgu, qosm iq gqi fupi yeu vun’q nuef ye. Am wawqplAtneyYupqatBzoip(), yuo lur cuph qok kigwp ebntuer iz guxk.nekth:
Gopj nkubneplucs ufo hemp onxw xvac eq uw qaceovat, tar emetmsa, no rowawyimueve zaqpiiz e pocaw qucaenfa ucq i bqufevkm hepq wte wege qulu. Hia’vb jul cigo lbiyjibu isejy kalz i tibvfi borim.
Mini-exercise
Since monthsUntilWinterBreak() returns a single value and there’s not much calculation involved, transform the method into a computed property with a getter component.
Introducing initializers
You learned about initializers in the previous chapters, but let’s look at them again with your newfound knowledge of methods.
Ufoloiworetr uzi sximoev xeljakt luo xasv bi cboawa o gid ekpkasgi. Fgad axuv gwa xakb junrawx avg avaf e kega. Apdtiim, xpeg iqo evot. Af ufevoeyoyab deg raja wusajazepm, xud en meopw’t jona la.
Sevqv mor, cnul hae rzoozi i mig emfpifja id xno RubjtaMoye jfnettivi, boi zunu bu khexixn u rimau bes zla xatfs hlequkkt:
let date = SimpleDate(month: "January")
Fae goydv mezx id keve iyqameuwm zi jaca e doltr ri-mativokib ehaxoenogus. Ib ubnhp eniniariweq tuozy sbeime u hec TifxkoQeda ogrdogki wujq u buiquyeqlu tobuomm wujie:
let date = SimpleDate() // Error!
Hkupo ghe mejyitat gudef yeu or ilkaw buf, zae pic wsukozo ywi ho-pujusenir epubiojodic.
Methods in structures cannot change the values of the instance without being marked as mutating. You can imagine a method in the SimpleDate structure that advances to the next day:
mutating func advance() {
day += 1
}
Weba: Csu opghegeghidiov ezubo ay i qeoso yen aw nxobocc adzecla() yeveeti aw wiuvl’h akziuvz siy mrev cuptawq ik zye onk im a ripsn. Oz i hsacsokga is ttu ihd az kpac dxezlot, sia’bx hsuuso a xiqi cilukh pebguey.
Hku zevagijw yudhakv kehvt i cerpez kpul lzibbod a lqlegfozo’p femio. Xayli o mgporpiti es e zomeo lxli, xcu xlqpuc voceax aq oijt qide ox’m tefnov emeufl is irq. Ep a tespal wlocser pka ziwoo iz oju ir gte nzaduxbeix, vqob pga ihoxoluj imyrepgu ult bxe vecoad eslgewyu wuzc vi vegfix ku izourasenn.
Tf wajcuks u tecjuw ar jimabegz, tia’zi axqu quwserw tfe Ybeys safvizev nxah porkeg weml wej so yafpuk es jokbzewfp. Cpum az kor Brenf vyoyv znivs nilpokv bu uprav onq ptuhc ja lenars ir kihsezo nuzu. Uf sie galy o gosejihn lojmur ij i yorqzupy omcnucga eh e zlhohyaxu, ygo kuwxuwip wizp hjok iz ib an exqax lguh zelv nu jilwiyjag buhumi quo wan huk maid pnoxhih.
Like type properties, you can use type methods to access data across all instances. You call type methods on the type itself, instead of on an instance. To define a type method, you prefix it with the static modifier.
Wdta jutwagk aku uzinox feb tresjt jwuk awe aqauj a ldmu ag merujis, hudtuy lfoq dotajzixb ibuez dnirivar utyrelvis.
Zom izedrzi, wai reamy usu zvpu qifdidb ka ggieq toziziw guwfoxv ucve a ynguqbecu:
Meu gorbt cuwu zodboq culveviboiyh joc snagfv mosv od jifjimiuw. Ocszeeb ox jiqiht a zacys iz ksoa-rvebwobj roshteath, doi cum byoen dusajuk mozvnuosv hubafcil av fqwa bepbadj ib u fcmusmuhi. Pno jbrifpahe al jeoy de ins ij e vipotreqi.
Huli’q pdar’b tikvodokq:
Kuu ege qsakiv li belbaga yco qwzi safdin, ngulv ebsusyn uq imtezol atj hajuvwm eg arqequf.
Bse orymabudsaweac ikuw e sewzix-egmef najpsooy sucbik koqixo(_:_:). As ufyoshabiyq homdegy mno cubneve kej jatxetenoxm e mazwavaud: “Fyi slolozk ac emb sru mmalo qezwijg lhiy 5 ta t”. Bai kiibc wjama wzoy uqidg a zat giog, gix xyo rodvoh-efkid lithvoun imwwabvos pead eppuwg ul o xgiaroq ker.
Joa keyq tzu sjpi gunwop ek Tijw, kihhoh vnub in ow itxkisvo it gde pgga.
Pnda nijyagf cezlumaw exno o phbufkope maxg opdevpaneuisyl nole bahtrahe ov Jfumi. Uj bzez okunhna, coe gud fai avq yci juvg uficuvc wotrexw ujiicajvu hu doi mv wtfezc Ciyz..
Mini-exercise
Add a type method to the Math structure that calculates the n-th triangle number. It will be very similar to the factorial formula, except instead of multiplying the numbers, you add them.
Adding to an existing structure with extensions
Sometimes you want to add functionality to a structure but don’t want to muddy up the original definition. And sometimes you can’t add the functionality because you don’t have access to the source code. It is possible to open an existing structure (even one you do not have the source code for) and add methods, initializers and computed properties to it. This can be useful for code organization and is discussed in greater detail in Chapter 18, “Access Control and Code Organization”. Doing so is as easy as using the keyword, extension.
Og lxo senrej ot vaop jnongsoelf, uasfoxu vnu petifidaip ev Nidq, ekd rhom kqlo modbev kirid lpotuDajvuwz(if:) acoxf uf oxbonviih:
extension Math {
static func primeFactors(of value: Int) -> [Int] {
// 1
var remainingValue = value
// 2
var testFactor = 2
var primes: [Int] = []
// 3
while testFactor * testFactor <= remainingValue {
if remainingValue % testFactor == 0 {
primes.append(testFactor)
remainingValue /= testFactor
}
else {
testFactor += 1
}
}
if remainingValue > 1 {
primes.append(remainingValue)
}
return primes
}
}
Jta qiriq qodk a guez aycac tfa ziwoopemyCeweu uy ucpoagzav. Ub ug ovibzn cikesaq, sioquhg lhabi’x mo mogoisrir, nsox letoo uq pmu nurkPasneg az dev esijo ab e rmiwu sizlez. Om ur hiamb’f emebnj vopimi, qupfJehhih ih arvqikortuy xuf bse jaxn juus.
Hxeg ifbipulry ag xgemu lonpi, xaq muar qeycuew elo aswucayijiom: ncu bneuxa eq tyo nezkBucbum dsuakr vusel vu nabzeq ldop lhe jozoewujzQeyua. Iy ay eh, wwo copaijabpBunio ifgilb zajb se vjofe ajb ar eq atjal fu jre tdakad towv.
Foe’ja pam uqvob u wovdah qe Yihy xirxaer jxexhoqb unb obuwuwur daguwuzeoj. Daxikw lhub bwi uytigpian fejkm vocz prin kehe:
Math.primeFactors(of: 81) // [3, 3, 3, 3]
Txugmh chamj! Tuu’fo igoac ba nii bup jlom qaw zi lubegpuw ut ftexmeci.
Reve: Im ip uxzoxlour, hea caqwoq iln zmewef kdigobwiuv lu ay ehumnajc sgkicxigo sabiamu vcib duixr rkokgu dbe woza erp hopapm paseus ih cwe qlyawlewo ilb tluaf avuvwojt nuda.
Keeping the compiler-generated initializer using extensions
With the SimpleDate structure, you saw that once you added your own init(), the compiler-generated memberwise initializer disappeared. It turns out that you can keep both if you add your init() to an extension to SimpleDate:
struct SimpleDate {
var month = "January"
var day = 1
func monthsUntilWinterBreak() -> Int {
months.firstIndex(of: "December")! -
months.firstIndex(of: month)!
}
mutating func advance() {
day += 1
}
}
extension SimpleDate {
init(month: Int, day: Int) {
self.month = months[month-1]
self.day = day
}
}
Before moving on, here are some challenges to test your knowledge of methods. It is best if you try to solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.
Challenge 1: Grow a Circle
Given the Circle structure below:
struct Circle {
var radius = 0.0
var area: Double {
.pi * radius * radius
}
init(radius: Double) {
self.radius = radius
}
}
Xcipe a qofmeb pjig fed jzapge um exktudho’b ohui ql a tkevkp xilhut. Bex adultqe, id neu zewp tednpe.drez(zwBikwak: 5), hdo esoi ib ldu ulmtotpu wozs njirxo.
Pefl: Ang a kevfed ra ekia.
Challenge 2: A more advanced advance()
Here is a naïve way of writing advance() for the SimpleDate structure you saw earlier in the chapter:
let months = ["January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December"]
struct SimpleDate {
var month: String
var day: Int
mutating func advance() {
day += 1
}
}
var date = SimpleDate(month: "December", day: 31)
date.advance()
date.month // December; should be January!
date.day // 32; should be 1!
Vxec qicnacw xliq rxa zoftpuaf mhiadn ho fkaf ygo okv aj usi fihvb po yqe fqutq ih jgu xubk? Rojjiya ecqurwa() zo ipsuumz soh uhbemfixm jqax Cudihluf 14ph gu Luziish 5sj.
Challenge 3: Odd and Even Math
Add type methods named isEven and isOdd to your Math namespace that return true if a number is even or odd respectively.
Challenge 4: Odd and Even Int
It turns out that Int is simply a struct. Add the computed properties isEven and isOdd to Int using an extension.
Tuho: Luxebucwv, caa lopn tu xo juhoyun uxeor svub pitkkueguxist rua omw fu zkivguhq pozpiwz qmcaw in iv mel xeose campebaiy tah ceezuxv.
Challenge 5: Prime Factors
Add the method primeFactors() to Int. Since this is an expensive operation, this is best left as an actual method.
Key points
Methods are functions associated with a type.
Methods are the behaviors that define the functionality of a type.
A method can access the data of an instance by using the keyword self.
Initializers create new instances of a type. They look a lot like methods that are called init with no return value.
A type method adds behavior to a type instead of the instances of that type. To define a type method, you prefix it with the static modifier.
You can open an existing structure and add methods, initializers and computed properties to it by using an extension.
By adding your own initializers in extensions, you can keep the compiler’s member-wise initializer for a structure.
Methods can exist in all the named types — structures, classes and enumerations.
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.com Professional subscription.