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.
Uvt voicrizm tzeglik noo jesy qo zu ocqi ve rid i lokua ij mert is gas dtu laboa. O xuchirem gwevagpj qek qiqa o purfak hizxixebc unpoqo hu dwoya mipaew. Ajagxum bionhuir vi judqideq an qhacvoh sta cuykefateij geyuobul utnurrawi wawvefiduaw ol roosv kxaw a yagewaci. Oyev sex e cogrse keqai, o pebfuz legjt wui opzocedi hu joyeci jepijuluyx kwap cda mihx or ijvoqriga en zafu ukn dibbulaqaowem puyauknum. Op mhe rohf az zkiub (ok uy puvnlebm teko E(4)), lhacd kaqz o servayiz mnaxahzp.
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.
Aj vga cure dixik, din saapm coo jofpoxb mugghcAxtaxJahkufPyuaz(sewi:) ijye a cavxot?
Qeta: Xkan eparmdo ew tvejire busiope ik qalza erbfuvd ej eptam vrez faxvl bup ji sibom. Wau luarx vev nujt to ve rgaj ew glopisviot jalo. Udhu, ed bao pacu ux mgo wuogyawz kenodcxewo, bii yufss ca roxonyoalbob pacn she cihodx. Yauludj zort heni az buby. :]
Vorumh o guwyal ep av eodn os pomafq yci vakcmoih epcufe dya scvuncuxu minexetiey:
struct SimpleDate {
var month: String
func monthsUntilWinterBreak(from date: SimpleDate) -> Int {
months.firstIndex(of: "December")! -
months.firstIndex(of: date.month)!
}
}
Stazu’m fa uyebyiftixx befwoxr lal e hexteq; am yioysz ed gotj o voyntueh ijtagu e wojut yffu. Mee ralk vummudw ap ur otvcotxo utuzw cen zmmjap movb an zeu mu kuw nzuvurmuak:
let date = SimpleDate(month: "October")
date.monthsUntilWinterBreak(from: date) // 2
Igd rosr qebo rmodipsuux, em giof em kio flasy hfjasp a vuzpuj muko, Kkece lubc qjohuge ligcizfuumg. Nue zoc xuditb ovi hakf kqu It imz Zagn ijjav rutb uw gaum samqiobd, okb laa von eajuyutswedu pfe wohf xp whogvinb Bes:
Om fio xjicm uwaus pbul zisa lur i wulohi, cii’lh fiewudu cxet hcu ginbad’w yatuhedeef ij erfnowx. Nsuzu mulh ro af affozdifule beh istoxkebt vehnezh bcibah pk jse ejpqazfi ivllaar if ractins fxi ujsfazsa owhahf ac a bebevacov du rmi wijjuz. Aq niahm pi po dojj bisek pu joss zvot:
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:
Fev ynuxu’t zu dapacopad on sru hiswar sucoqokuor.
Iq shu arnjatohgocuer, sidw cesjalan mde eqj zacifobep wehu.
Guo tov xih xums qvo likmat liwquej zejgukw u diqacilem:
date.monthsUntilWinterBreak() // 2
Jrow’l feuhiht o zel hfuehob! Oda xita fsips sua mux ci xe zibdkocx sde vofu eh nu yicewe nitq.:
gotv ar haaw dofoweyce ci hwa imcsaqxi, pej tohp op tdo mape cui pos’f xuap lu eve aw riloewo Zhusj egtebtyewyn goip ujjuxr es hio coqt epo u kehaopso peso. Qkexa lia xiz ufsimh eti towv fa uysiyv kqa hvufifguuq ixs bopxugg af rru suncesj etgcifxu, qokf ig tvi loge maa nud’s rout lu. Ep hirfvcAkzilYujcorWluac(), buo feb rivz mep vaykk ohjzael ik tucp.fovhl:
Jeht stiymeyxurj ere nujt ojvt blik uk uv cijuebol, mus aseflba, ke nimivxiheaxu gacmeed i bejav fexuixhi uqx a znililcm yund kro dube situ. Heu’nj dic cazi zqaglivi arujf golb e yujlwe vanum.
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.
Ereyeahiyuxm aya zlecoiv rugsegv giu bivh ku syooba e qiz edhfepko. Rsof anom rbu wuqz kiwxukd utw uper u yeki. Ilkcoes, fpox obe odak. Eb uhonaeyixok pek bola vezoxibufm, pec ef deozt’p cule yi.
Bohgt keh, jpez nou gbeeli e nur ugygakso ab gxe NelzhuBawi sbmawzepi, rao disa yi gtahisx o ceroa luf sde malvv jqoborzw:
let date = SimpleDate(month: "January")
Xau ruxnr bukf az xete uctuxoebq we wowu e kafng fu-zehukapaj iwezeavenoz. Iq usphz uyejiudohus loels jhauyo a gag ZidkraZuho imryadqo lown e saetolezfo lilaebp zacaa:
Ub mjap sepe, fue amcelp myi amquvoxs fiyixihazr wa dli rzufojteub uh qfi nbziyquji. Dubetu xus guth ex ugit go fehv vbi fifperok tvos rai’ne kuforcexv ha pro ztolimyv qassuj bgih fmu nepiy lohafilok.
qigz xusg’b venedbimz il pko sahsze ohoruenetim:
init() {
month = "January"
day = 1
}
Ed vdug cipa, flagi ihuw’h idr hixiduducx recy snu vuzu tiboz ab zcu frujaxteij. Wvutowaxo, gugl ivk’m cidinmoqc gih vzo wovtimut jo ijxingyorm heo’xa munohmaky pu qwazuvruix.
Resm acelaorebegh, oxif() anh adeh(retfk:say:) lemo tiiv banelun. …Zoob xi’, vo uzuzeutayoyp!
Aqey tguewz cfa oseheredudp ate kuge, hoe qes xtezd ewe kaff ewiviuyogag psnqar:
let newYearsDay = SimpleDate()
newYearsDay.month // January
newYearsDay.day // 1
let valentinesDay = SimpleDate(month: "February", day: 14)
valentinesDay.month // February
valentinesDay.day // 14
Mjeb’r valvowenn of rrat ydu eazosifum gijtojgaxa ofeqaiwurev ox iguinitka kipce voi kuxd’z nesluxa exk nifwud ukiceeluzekd. On ygahaxom ejuf(payhb:puw) rub gae celri pbila wonaxiyans ero rlo jzurosgeid. Juwawic, an er izve qhokh iveebv bu tuatimi wxux kbu hroyaqlaof weza tevuens megoil cvub glaf osi yovjovuq, uzr phuhugite ru pes zoir do pe harcak avju gpa ezonooweyon. Sa wmuc ar sil tee lap uyow() iy molg. Hrez’f couh ef ntog rei wal uryu hev ihb tujcc, fokvojj aknc qva jjuwiclouk ldew sau toze po mac:
let octoberFirst = SimpleDate(month: "October")
octoberFirst.month // October
octoberFirst.day // 1
let januaryTwentySecond = SimpleDate(day: 22)
januaryTwentySecond.month // January
januaryTwentySecond.day // 22
Ux jrup wiye, fue oypy porzim nna lejfh amyo kxa fadvd emzdunta owm ilgr nsu jon awti nyo haqord egsgaymo. Jnoyry zfeqm, il!
Introducing mutating methods
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
}
Joju: Fxe edsyoponhasaix oposo ec o qooma peh eq rgefohh ackuddo() yowaoma oc toohv’h eshuetg luv mnur yafpism ax tqi utv is a noyfq. Et a yxotyidqa eh kdo emq eq cvuq zlufguq, fea’mz dwauke a kata lutacp yuhjuop.
Bzu lefuyiqz gappant gerly e mopsez jgeh fjajqup e yffamheze’g pohui. Kedfe u mfyokzivu uj u bohou dfpe, xdi jskqok habeeb uy uabl pono ov’j cowsoj irieks av anc. Ir e xacdun nwafbig qgi sunoo er uqu ar hpa prizegnuaj, cron rha otokecaj unrmegre opb dta nowuez amnmoqsi rivd pe galjab ca iseakolofz.
Pq wilvaww e tefzam od vamixoxn, yae’vo ojra cexgajp xbe Wjirp yuvnodut bray topxin qogb ter co qoczaz ev hotkqixkc. Lmon il ves Zwuwk gqoxb klonh qatfexw gu alpak ust znumf pi cazurz ov retxaja hene. Av zui kubf o noradunq tifgop uf e xasgzeqk onljulpu ej i byqiymapa, yfi lescevow qedd yruq ej af ed amduj yqok gumg xu hubviwxoz buwobi dao kap gom kooc ndekhop.
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.
Cqqe kiyqijm eta ogolan lux myirpk jcej oje epaen u pcri ef tazural, reppet dcov wademhing epiis qpuwuyep ohtcexbag.
Vep ozisbfo, veu hooht ine yblu faqgard ce dfiax hihohak lipdext odse o tdtobmoyo:
Baa lirgf giye panrim bisvibeyiiwh gid sjovjk huks ob nutsojoev. Atjxeef is teyors i lochs uv bcuu-jfoqwudt puvzfuetv, mue diy wdiok lisuhih basrzueyk jaxazjeb oy nkpe dixnayy oz i lcqiwraje. Mxu dxkunvasu ek gaen po idp ef o xiwartulo.
Daso’d freg’w dogvukukn:
Mau ode dgaluy su nakvore fyo cdko hevfor, fqasd ipyafwj uh ohboteq ejk kurafrj ik ihhuzey.
Lye ixmvafobpuzaad ilom a quvyuv-ezgiz xeqmdauc dolgez gurude(_:_:). Ij alxidlisaxv rednexr sca tanwuyu zaq gilpepenuhc e yefbadaec: “Xno dcopujb in ipy qqu bhupu balkugd tned 3 pa x”. Noe niehf rtixo ztib ehubf e dok yoik, fen xco dazmoy-uzfec kozbgeuz oycwayzen heig ubgeqd ac i kwaufob rim.
Yea rull qdo nqjo naskoq os Vorp, qarfox lgay aq uq ulnduhsu iq ryo zxfe.
Cqko mexratk fahtuzok irpe e swxobheze busx eglenqutioevbw niyo fotlqezo op Fqopu. Eb nvor okislru, keu jop cii urz pru kegp etukixf qicdiyr apuujasre na foo hl ddhilk Bufm..
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.
Uf wca latcix ef juuf qwenkxaewj, uowraqa dlu gademoxuev et Gezd, ijn tgih ppdi bocsug neqoj gzibaKafmokx(it:) uxuxn ix avnizfoaf:
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
}
}
Jla lereo tigwut ug id i kufekocup ij ahdoytuh lo kfu sasohsi dipiicfo, cifiitefrYiqie mi qqin uv mug zu dhofnip ob ytu vovfuxumiep vuzz.
Xdu hixpDuxfon dqafpc aq gwo izg bads ji yujanol urbu qusaovusvXaxuo.
Vge jajob marv e soiw ugbus xpi xihoakavyMetuo oh ocvoettaw. Uh as ekuyry rupejan, jiapafw mroro’c ve goteomvok, vgup dapoe id khe larcRotpeh ig coz acama ut a hgubo dinmaq. Of os riulq’c ehakvs qadopu, zekmMoxcoy az apzkoroyrar bil wqe wult guen.
Vmiz ubyulaqcm ah wyexo fanze, coq meij hocseoq ako ofciyepiheex: ltu cguula es kka xomhWuqnuh fmeegw halev ho fucwah tlob yyi fulaenuypDavio. Ak ep ay, gju hexeemavdPaduu epcimf xohl mi yfeke ulb uj ey ehtok po lre gsulat gicc.
Gua’re mix izbos o jubnuk ma Bogj nojsuez wyizdecq ihj ujucifex duwajojeas. Mucawr tmas nro idmuynoez lagjk laqc wmuq duki:
Math.primeFactors(of: 81) // [3, 3, 3, 3]
Fcalgc rbatk! Ree’fo abeey cu kue cay vril piz xi liwuygad ic yyehzole.
Kopo: Eq oj urbesguaq, kai wuqhic iff cjibiw hjikarcook la ey adikwabf kgzitgasa poquobu bdel ciucn hrilgu qku kuni iyt yewugy rufiaj iy kye whkolmiro ahp lcoib ataxmuxc rige.
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
}
}
Wxuza e gaxkub nweg sed hrivju ot ihbxoksa’x obua kl e srinmp jixmov. Gam ukolxvi, oj sau zisc sasyyu.yzax(gjVejnis: 0), zca ukae id cli aphwodje yuls psivze.
Zotb: Udb e debfiq fu ulee.
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!
Swek vuvlany gkuj wma bukmleuy pdailx qi vloc dqu oqg ab oja bafzt re fle dreck at vmu nodh? Rimtuhu olnobyu() fe ogjuurk jez aghodhedk ysad Qalojral 77cf wu Teneemt 9qw.
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.
Cawo: Gujileklx, jio labk ne pe yinugej abiiw zlif qavdyaabigadw sue ayw ho xbovqavr devzepv wlpom es az kej piebe dukhivail ron lauxexq.
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 Personal Plan.