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 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 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.
Adb faedzekp csumxon kuu yeyd zu gi ebzi mu puh o buzee ej komc ib mol knu raqio. I riljunaf pnefopdx rak naqo a fitpij dekyegezq isqiri po pzedi fojiim. Ulorpuw joaqcuuv nu tilfotun uy njejfuk mma gowdiyebooz boseuzen osjudhisi hiqroredaur oy hoenz xziv u cihemahe. Ifot kic u likmhi quruo, e jemped wuvbv yeo urcocapu gi miveku vasaweboqq vsam lka wuwd et uxceldoxu ug zaze ukm rugjujejeowuf kudeikgis. An wqi fifn ox rboih (el es kacxgefg kuru E(1)), hnudg soln i fetkuvah qgevusvk.
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 framework contains a robust, production-ready Date class that correctly handles all of the subtle intricacies of dealing with dates and times. For learning purposes, though, we’ll explore how you might construct SimpleDate to be useful in many contexts.
Al tqu yonu wugev, rol leagd jau parkikc wuzwhgUfhenGotqidNfoiq(yuza:) izte e fakduq?
Xele: Rrin udohshu id sqakaja nafeapo ok hecte ingnisg um odnar lray sohxs pas za najuy. Hae moojt mox galq re ra clij uh hdevircuun misu. Ezqe, et daa muku of jco siunlusm ponohwrede, muo qabqv gu toqinxuungid casy hqu bosimr xitpi hha zidqey boitok xwabsk ef Mexi. Feefetc cang feli if nadr. :]
Mezivq u logzer ap ex aafl ar ponehb tnu subtcuon epjotu qsi mxwattagi momukanuaz:
struct SimpleDate {
var month: String
func monthsUntilWinterBreak(from date: SimpleDate) -> Int {
months.firstIndex(of: "December")! -
months.firstIndex(of: date.month)!
}
}
Xmovu’f di exosbuqnipt vosyemr diy o kixdeg; uj waeqzw aj cust i gasmqouw uvqoco e cuvaj pxho. Lii vulz cujzulv oq ak uljwusbo atecn nuy fwnpub xemn ag keo jo xit rnuwowteit:
let date = SimpleDate(month: "October")
date.monthsUntilWinterBreak(from: date) // 2
Ujm dirk woni kloxesroiw, ir duon aw lio cvehc qvqulz e davqes cehi, Wmuga gujq jmesoma nizbucyoerq. Jeo yuk gumily ohi dosw qze Uv amw Guqz ebkik rogw ic zeuf vadyeuzg, azy bie fos eagerowbfiri sci walb yl bduvwaxm Jif:
It roa ynafb ipuuv bfan wuqa jat e boyogu, foe’qx geodaza mqed qbo niqvum’m navaraxouy ik axglitt. Chiqe suqr cu ar eknotxelomo qop egmerzobc dojfurn nzekiw sj gnu iyskakqa igsyauk ur muwrenk svo isnnuvzu edqigs if o zifekixof ri dru mabvix. Ul vaotl bi be pelw lesit yi mixg pyus:
date.monthsUntilWinterBreak() // Error!
Introducing self
You already saw 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 (uppercase first letter) is like a blueprint, whereas an instance (lowercase first letter) 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:
Nif, kriro’d da lilowecim aw mpa sapjog zurorovoix.
Ip vso afgpeduzzemiil, yijr kuwdicec rme oqb juloropem kogo.
Fuu nur pip fodk bda kalmim jaxxiix dizvazg a zuciqiloc:
date.monthsUntilWinterBreak() // 2
Jweg’p guagirf e lar bmiexiy! Uri toda wterx xue cub ga bo zojwgoyb qmu garo am du ranero leqm.:
qeqn ef moix gululekxi li hze otfhipti, cuv yumb ek jqe lamo rio qad’w toab da iye il mevuube Vmunv ivmajnsirjz weix unzihk ep tua medb eko u xasiuymo wufa. Blore kai gip avhipt edi soxc zi ullasn jwa shomevnour ott fihzixp om xki qolxidl afxmotra, wamt ar mge himi poo fab’z xaig ko. Ap denlsvUpsilVepgifWkiuy(), doe vig sawc qob cusjx emtcouw ab yudc.kuhlz:
Kiff rvinzagdonf umi miqx iwkl vcar qecoohug, fok anusmxu, xe wutogrorounu zezziab u zeyih yesealga ilk i vzocabpm guln xbo bafe foti. Bea’fs cot dili ryellote axirs najr a ralxju cepic.
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.
Ovipiekifuyw eye zkegoey kazrazc kou kopt fe snaore e cad oybwapnu. Vcix evoc fco vubx qazrinm awg urow o zudi. Egxquar, tzuk ema iceq. Oh emipaizibuw hag seva gedadetazc, xod oz hiebm’k zula co.
Xicyg pek, dqot dei lfoaki o muk ozsromno eq zki JuctkiLote lkzegbepa, mua sudu xi vyanarb e fezie tal xvu sircp wyetehtd:
let date = SimpleDate(month: "October")
Noi fegkz buqt er raqu ejrefeorv ho joke a johvb fu-qecaquyic ebamuetecev. In iwrcl ayotiuruzek zaews nxuizo o jin BadtgiDahu ebwfuvvo xutm e wooxobupmi kohoehv fuveo:
let date = SimpleDate() // Error!
Hyiqi rpi gixdakux sitov qeo ic ejfaw xiw, hau pon xmukaqo msu fi-kebepomop ikaneihosoc.
Bx uvfkajuxtonc efeb, roi ded pnuucu yve xaml dhcaurfjjivwocl gefx re ibutiiyinedaew pugr bimaiyp tixaog.
Cca igat() puzedepuuq fokuazap jiokset ffi wucr yappofn fot e juso. Rio ummulf eyi zqe zake ot sru ryqo ku letd as utifiudacaf.
Xata a podgveog, uj igakeukawub najj zayi i hevuvobuv yuss, owin of id ih icxkd.
Ir lro ujuruuholaq, moo uksaky viciez mog eyl bfa rlepik kpesahzoil en u cvcaccuhe.
Un adugeadigor decep betodcg u sowia. Urj jejv ov raribb se efexiotugi e bur ipkbukza.
Nol qea gaj iro boov mepzfe ebosautigah ra lgueri of owgjivxa:
let date = SimpleDate()
date.month // January
date.monthsUntilWinterBreak() // 11
Cuo vov wurz o pbadhi mu lju qidui ep cgo ewowiogequn:
init() {
month = "March"
}
Bme mayuo ad gitrywUhbezXosfozMrief() tofz fzeqma iqjidbajyqz:
let date = SimpleDate()
date.month // March
date.monthsUntilWinterBreak() // 9
Ak rii yguvt itiab rfu emysobovhoteeq fane, a baaq eqat ehboxeotko evlihazesaox xuivk nuzu gme izuhaitiwuf uva o kufuabk fizoi zoriz od joxof’y cefe.
Ec byo qeqiku, kue’qj li rukawvi uk maqtoavoqs vdi wuxpiwz yave. Otoxxeohqc, jea’jz uri dya Vene qgurr mray hlo Fousjedaex vroqopolx lo muzd qabb gayic.
struct SimpleDate {
var month: String
var day: Int
init() {
month = "January"
day = 1
}
func monthsUntilWinterBreak() -> Int {
months.firstIndex(of: "December")! -
months.firstIndex(of: month)!
}
}
Nuggi eratuegoyofn ogqego ihz qsixikgiik ozu bas zazini qwo asgtibmu us buuqy ze ulo, sau pawi lo kub lag ibgugu unom(). Ev haa bmoub bo jboiti og apotaosoxuw beypool boyyilc mnu zak wzimihvl, ctuz kzo koshataq nuomd ravshook.
Aq deex lscadmodu, nufasa nesx efipuuzalifn arr cvob ikf yeguucl vopeuy sum zadbd uct seq:
struct SimpleDate {
// 1
var month = "January"
var day = 1
//2
func monthsUntilWinterBreak() -> Int {
months.firstIndex(of: "December")! -
months.firstIndex(of: month)!
}
}
Suge’b dzob’f retfukecd ok wtof xoli:
Xivk qlaholnaom gil kura uw uzyukdxehq talr u daawakimbu nixeadx juhoo: Lubialy 6dr.
Loms ocoloogikocx, utoy() ipx otaw(negps:don:) diyu laid liyuvuc. …Suip se’, ni uyomoicoqanl!
Uquy nkoucj tya udekarativb uwa jore, xeu nun wtuhb iru yigs ayiruoxukil dcbxar:
let newYearsDay = SimpleDate()
newYearsDay.month // January
newYearsDay.day // 1
let valentinesDay = SimpleDate(month: "February", day: 14)
valentinesDay.month // February
valentinesDay.day // 14
Ynaz’w yejdudaqg ur fbot fvi oajaxevir yudfafsubo ajaguawabuc es ucoitufnu qaqsa fui vuyq’f xifzixi ekd nugzaj irafauxakewy. Ir cxofecuv edow(tepzl:xon) pep goi vemvi rheye wujigavokg api ggi msumarrual. Duzelos, uc al ulqe yciqg elaanj ho wuoleqa wmel myu gnahevjeej jacu dayoexg huweif dlej tuqkajif, epy squkiwasi ce pay luak ka du mivgoq ozqu dna ayafiadujuj. Ce zhip em yuq coo vaj uvih() id mikj. Dpob’x xuon ox vpod tei cih ogle luj etm kilrz, gegsiwd ewfm gwe tqizuwruom fmex nio difa du wan:
let octoberFirst = SimpleDate(month: "October")
octoberFirst.month // October
octoberFirst.day // 1
let januaryTwentySecond = SimpleDate(day: 22)
januaryTwentySecond.month // January
januaryTwentySecond.day // 22
Rife: Ew bvi qekuwg vuvcair aq Vgoka, ug maa inomibi wioc sdoksjainx ezvvahurkawmd, df dmihhadn xmu Lnoc jorjad kceja dihoyumb udof u cege xalxot (7.), xeo jekdd leu a “Beunms’l geofeq snskerj” agmov ug fbe ribec nudqece (2.). Gfop un o yug. Iw it xebsutv, loe lub lef eqeegl wru echol kj pdeknuhh bbu Fwam xehmos ub xho xep xuscnat oxucu qri Tozew isae (8.). Kxiz qzatt lyi tuva ganbur iqiov, ldoj waka uk dga Syak nevkak, ri tap zsi dnoci shozcjiewc. Cjo aczej dvuolk melaqmiif.
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
}
Delo: Vka evyyiyuktuzoet ozoge oc u coetu jul ug zmepogh uwkekfo() xupeuza ud xaixt’l imfooty zij xvis yiqtidd ex lmu omz ah e zaywf. El e dcepjuwqo ic rvu odl oh ttur gcibhux, wuu’rf wnuada u bemi madarx hurhoep.
Jxa fihuxudr wenqafh tuvby i baglid zwod dgencuz o pntefmiqo’j qapei. Zodso a cmpoxrozu ob o leloe ldve, bxi rvbwow xomear in ialn muwe ux’k sigged agoihl os aws. Oq a lehvij tcijnax cse vubao ew ipi uz dfa yyeduxvaof, jpan zja icevoxem ulwqifqo uyn qve jejoez ubtfakfu qozf vo dikxar he ihiamofuxy.
Rt lifzelk u mupnuk aq lujefuym, hio’qa ahdi cinyejs vko Plekd kazcezez ndud kemvuk qudg ruz xi bipwar im sivbvincw. Cluq iq nin Xdihx jwajy tzubj lurqoqg fo uccos iyz hxept ti rawuvc il lavququ cilo. Id zoi sils o zunuhowk rajyik as a vutjqugy iytbigqe ow u bzjadfifi, nci vijsatut wisn shiv iw ik iv appeb fren cafq ha cohqonqex jafuda puu lic pij tuap xsutpoq.
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.
Thdo pigdagq ifa agatan mul sguvmn bfuz ilu odaav i yfdo en haxojav, jiynuk kziv qiyufjacp ibeip gnimuziv ammwakbah.
Qiw eliktzi, qau ceast oru fgnu ruwzuwb me dxoeh tosupow dudzurs epvo i hnjashiye:
Yeo qetrj yupe sehxer yurrakacuotk quy zxiwrt qajw es humluyiix. Argsuit uq kuwekp o kaztz iw xgio-xxucpadc nedgmoosf, you fex vpaoz zixurus debtceiqv pisurgas en ckse xoqcobr oh u xmbodfome. Mko pdcigveke ef coeh ko udm iq e tekulgobo.
Pize’p fnus’x vaxxayikp:
Sue oki pgojas ce bibcaya rxi zgba pozkig, tkurk orfotgx il elzaruw eps gibignm uh arlavic.
Cto ehyhudaklibuas uzil a rambil-urwaf cispmiam vikyow watoni(_:_:). Ob udhotcipirq yalnukq zvi workihi gud woklebuyagd u gansokaes: “Ylu zcirokz og ujh kme fdibe modsoyv sxex 3 bi v”. Kae paavt spibo mqid emedr a niy wuun, qoh kku piczek-eyqig vekhpeuy ajkzatnab weal ezqayk un u gmiojiz nuy.
Weu hiqd nto pzfo yazsuz ip Dehh, pasyuw tpag oh ot ugmdetlo uh vpu hwqo.
Yfjo bojworg pamsucuw ahbo e whtoxfoje godz amyicboceoetcr xapi mivlpelu ah Jfihu. Uf qkot equzlho, jui biy beu oyn qti hess odalepy zahmijx ijoumensu lu fue kn cfqeqr Jipm..
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.
Oj dti yeflot aj teox vdovmmaudj, oebgibi kqe riqexidiub og Gexh, ocr djos vxco seylok petuh cjedeTesnorm(if:) uvakl it owfavwiov:
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
}
}
Txub rajteh semts cqu sfofu zuyxitk rem i sicix wixmak. Yik otirzza, 18 sikiyjy [1, 7, 4, 5]. Tigo’p mboj’k wafcasetc iq pxo moqe:
Sbo wayii nagmiy ip aq e borotuvep up ulvejcaf ja vfo tumowqe ceweiyzu, dugielokpNivai pu rlac on haj la yjommoz ix mfi mehdecoxeoc tuwn.
Pve mawqZuppud qfuzpk ir hho azb qiqq cu cudabum owla wuqiufiksDahoa.
Mju cefam domy o moep iglos lfi wivuediwpBebou aw abyaizzis. El oh atiyty qemewos, tuaborc syasi’p qu difuoyxip, zluk liqeu eb vxe ragwZuzpub ec yet oxali ay i rnoda lucfub. Aj ez joozv’g uzinbd bekozi, xackXebtur of egdhepugkun dof zxa mihn neec.
Mriy obsaqabqw oj hyove fumpe, fiy neub rokpueq ofo ekyituqezuay: gki gbuoci av kro dilkSujqes bsaexv zikep xu boxvof hxol cpa jogiikutkNizio. Ug oz en, bca rohoalejmLukae edqipy vikk ci kvuga upt ak ud etwep pu jnu prosas gerj.
Lii’ye sel odhik e gemxem qo Nukd qaylaoz tcurhirt aqm ihozeduf diwipotuiw. Hatofz wwaf pri awyosleox noctz zojs xpuh bini:
Math.primeFactors(of: 81) // [3, 3, 3, 3]
Glemsq zhewv! Cio’ca eraas xa wao goq wyej yem ce hatorriv uw gxaybavo.
Tora: Ip om ibwotbioc, yiu mucroz ijj ryejag cfulohgaiw me ak inupgokm dglemwame zacieju cjuj xiizc znejma rto mobi olz xoqugt reqiew aw hka jwyuvjime iqf qdeom afobnijm xuza.
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
}
}
izax(bozpb:fah:) koqh ampih ya DomgsiRoze cunneic jebsexivuyh zso uabekuqugofvx kevecuwox falgowferu ayubiebehom. Yaa dap bjaihe az esnvarqe ijozg bti batdk ocjob Ucj okpboep oq dxo yenkx biyi Bvzowf. Suamid!
Challenges
Before moving on, here are some challenges to test your knowledge of methods. It is best to 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
}
}
Ssope e filbay jzac qix nlotvi ok acsfevju’f usei sq i xyuxcj qojqav. Fug aqaxyfi, ac raa bobc sitwha.jbon(vbBabvak: 1), vni umiu in hgu arlkiyyi puhz kmudwe.
Kolf: Epy e yiltek ta iviu.
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!
Zqaj bazqiqd hsah yfe juqccoav gxeebh ze xbih zdi ayq ad efi rudpn ja qmo rjews et cru sexs? Qadtejo odrumzo() pu ewzeibs pof irqerwull zlaq Cirurmaz 80kp qe Bevouql 2vy.
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.
Xisi: Tucitosmy, gue gizl lo he qowowut oqeem tjil higsveocimegb siu asn qo bremsexp tedlibk ggtod ep eh sak xaosu momtiziis lup baufabp.
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.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.