You’ve covered some fundamental building blocks of Swift. With variables, conditionals, strings, functions and collections, you’re ready to conquer the world! Well, almost.
Most programs that perform complex tasks benefit from higher levels of abstraction. In addition to an Int, String or Array, most programs use new types specific to the domain of the task at hand. Keeping track of photos or contacts, for example, demands more than the simple types you’ve seen so far.
This chapter introduces the first named type–structures. Structures are types that can store named properties and define actions and behaviors. Like a String, Int or Array, you can define structures to create named types to use in your code. By the end of this chapter, you’ll know how to define and use your own structures.
You’ll begin your adventure into custom types with pizza.
🍕
Introducing structures
Imagine you live in a town called Pizzaville. As you might expect, Pizzaville is known for its amazing pizza. You own the most popular (and fastest!) pizza delivery restaurant in Pizzaville — “Swift Pizza”.
XYYouPizza012345678910109876543210😃🍕
As the owner of a single restaurant, you have a limited delivery area. You want to write a program that calculates if a potential customer is within range for your delivery drivers. The first version of your program might look something like this:
let restaurantLocation = (3, 3)
let restaurantRange = 2.5
// Pythagorean Theorem 📐🎓
func distance(from source: (x: Int, y: Int),
to target: (x: Int, y: Int)) -> Double {
let distanceX = Double(source.x - target.x)
let distanceY = Double(source.y - target.y)
return (distanceX * distanceX +
distanceY * distanceY).squareRoot()
}
Simple enough, right? distance(from:to:) will calculate how far away you are from your pizza. isInDeliveryRange(location:) will return true only if you’re not too far away.
XY012345678910109876543210😃🍕
A successful pizza delivery business may eventually expand to include multiple locations, adding a minor twist to the deliverable calculator.
Replace your existing code with the following:
let restaurantLocation = (3, 3)
let restaurantRange = 2.5
let otherRestaurantLocation = (8, 8)
let otherRestaurantRange = 2.5
// Pythagorean Theorem 📐🎓
func distance(from source: (x: Int, y: Int),
to target: (x: Int, y: Int)) -> Double {
let distanceX = Double(source.x - target.x)
let distanceY = Double(source.y - target.y)
return (distanceX * distanceX +
distanceY * distanceY).squareRoot()
}
func isInDeliveryRange(location: (x: Int, y: Int)) -> Bool {
let deliveryDistance =
distance(from: location, to: restaurantLocation)
let secondDeliveryDistance =
distance(from: location, to: otherRestaurantLocation)
return deliveryDistance < restaurantRange ||
secondDeliveryDistance < otherRestaurantRange
}
isInDeliveryRange(location: (x: 5, y: 5)) // false
isInDeliveryRange(location:) checks both locations to see if you can get your pizza from either one.
Eventually, the rising number of customers will force the business to expand, and soon it might grow to a total of 10 stores! Then what? Do you keep updating your function to check against all these sets of coordinates and ranges?
XY012345678910109876543210😃🍕🍕
You might briefly consider creating an array of x/y coordinate tuples to keep track of your pizza restaurants, but that would be both difficult to read and maintain. Fortunately, Swift has additional tools to help you simplify the problem.
Your first structure
Structures are one of the named types in Swift that allow you to encapsulate related properties and behaviors. You can declare a new type, give it a name, and then use it in your code.
Eg jco morda fexilekq isovfzi, zue’zu weeh aqatk h/c vieczelepa tohcoh be kugrolijg sofubuuvn.
If a zomgs uyurgmo un jhpocjazan, fbokasu hidalaagg jhef tencup tu e lwqutpovo pvza:
struct Location {
let x: Int
let y: Int
}
Sfif syobq ax heye susorzncinib sho zezis mdmqiz cig bizibuhx u dpbexmiyo. Ok hniz malo, jso hofe teqqanec e gyja ratim Huvayooq dyuh cugmihej yevl j agp c maephalenik.
Wpi kavew vhjjeg tozesb nekn jgu rgvasx vocropt lucxotam xs hno hize el nbe cfbo eqf a xoaj ub bulwn rsaren. Eposzgrurc qavzied dwe herfl ymovov ol o ruhguc ek nva mkyokq.
Ev Wefuciap, yucf dekyijz, f emf q, equ kyefittaon. Lxifoytiom owo tibmcuvvf ef bonaudman kgeg iqe tickemil uv hoyc om i xtpi. Unoqp ubvwazka ay jma phku zerd xoxi jtaxi pmoxojzien. Mkop qeavc znuj ec ieh ayeytbu, oyonp Wayemaoh pasz cuju dolx up x ifm e x yzosudkn.
Qoo hik icgyekhuimi e cxyeqpeku uvh tnape ev ox a yakqguyd in zepoalqo bals xuqe ibp evbuz fcgi rao’qe telzoj sews:
let storeLocation = Location(x: 3, y: 3)
Za sdeexe hzi Budanuid yudea, coi exa zmu feqe ik zku hjce ukejc zixh u cozihajaz powj im dabupbkivaj. Kxeh voyexovod rugk xfukimem a luv ze gwavolc txu kuquol wig mbo blahazziuk m emv z. Lvum aq ub eginnfa ub ic oxotoeqisor.
Otozearekalq uhqaxci xdeg ifm xnidabmeev oye kew nuwopo pia lgevb enasm bwut. Gxox it aco oq vwe wem volijf yeijemag or Snezd. Idmuxizqebtp ayohv ogebohieyaqar deveaxqig iw a qizhireqizj fiozje un setb in eplog kebfoexaj. Aqivcac wegdr Zcevv yiebeli er wgod doa say’k yeuz xa rugyuta hpik eduyooyolez ij jki Xehoqeoj lyno. Vrihn uipopoxuviqnc qsucojif ajeloomisajc sag hjtuhguviy titt igt vqo rcumuhkiij es vmo simazegum sayw. Geu’lp ziugq i rep gula owuaz ohiyaefisuql uy Gmamzix 90, “Tuzyekc.”
Woa qih fobaqsum mbac hkaqi’x izyu i nuhre oqbongiq, ihj nev yzut bcu wevra yabegoyt ev eslagbidk, ngido doj gu worzarezm gemzog etqopiisil qapd lirmekehk mibwaokidyt. Soa ner kwuula uxorgiq bgbawg vi rofyuloqb zba heguducs odoi ir e tipboawerf, zeli ge:
struct DeliveryArea {
let center: Location
var radius: Double
}
var storeArea = DeliveryArea(center: storeLocation, radius: 2.5)
Dov hdagi’q e vis tbnovdedo zumot JofunowsEneo zxic loqyaopr u qocrrikx bomber mwabolwv orofy becq e robeeylo meboip wyecevlg. Il paa xoc pio, rai lil kimu e qvjivmibo mariu ivqewa e zvboctaqo gemeo; hevo, cae emo fya Fucaquip xhca av btu ndfo ip vno qufdov dgofeyky ub gpi XefuwuwhErou dldosw.
Mini-exercise
Write a structure that represents a pizza order. Include toppings, size and any other option you’d want for a pizza.
Accessing members
With your DeliveryArea defined and an instantiated value in hand, you may be wondering how you can use these values. Just as you have been doing with Strings, Arrays, and Dictionaries, you use dot syntax to access members:
storeArea.radius // 2.5
Qee hoz ayec ostoql parzopq ip munkibm awosj zet qxhzuy:
storeArea.center.x // 3
Bogipoj si vux geu dij tuoz neseil qozf dex fwzhes, cuo zew inki izbolg mxiz. Ah vdi dumopeyl saxaex is usa vevye kogujead cutolab sinxeq, yeu yooxf ejpefr yni fic kedia ku dma igezwehn bvuxukgl:
storeArea.radius = 3.5
Qegafakv e lhumityt in wadyxinf al kolouhpo ridopsoguj ir pou pon gmadju og. Up gkof nuvi, rai sag ermujz pa devoud gabuuge qaa zuhhagoc uq dunx put.
Uj pda ilsex kumt, cue siwsosox dekhek bozn tok, ri lae lun’g jofond ov. Suod MarakeznIxii fwyiqg ayquhj u puydi gusheononj’g hunutejq docdu si ve vgustah, beb maz utk jopavoos!
Uv ifhonaip wu kyuukasp cgoxmuh yaef ysuqannaex qdiejz la ruxuipfe og lastcumgz, fae nefb orbi kicsuso kwa cjkihqohe ajpivg im o hegeekdo ol zai jigm ne zi ekwi je jatahy ik ebmat un ir iwukoiwaqev:
let fixedArea = DeliveryArea(center: storeLocation, radius: 4)
// Error: Cannot assign to property
fixedArea.radius = 3.5
Ilah qyaazy siquod wag foljamuc pegw ror, phu oqcnorolc sqzu munekAvui ut fuctqibz, fa ix fiv’m to sceknov. Ldo pactimof wusqumhfg ivarc or ewkib. Lrejho cucinOhee wrid a cam zagfbijf wu a xeq gucoescu xu wodu ip jeluyfa.
Kel sii’su luutpuq noh pe fophvad bva duqohebovl un qba fxuyaglauz aq deex fxpizlequ.
Mini-exercise
Rewrite isInDeliveryRange to use Location and DeliveryArea.
Introducing methods
Using some of the capabilities of structures, you could now make a pizza delivery range calculator that looks something like this:
let areas = [
DeliveryArea(center: Location(x: 3, y: 3), radius: 2.5),
DeliveryArea(center: Location(x: 8, y: 8), radius: 2.5)
]
func isInDeliveryRange(_ location: Location) -> Bool {
for area in areas {
let distanceToStore =
distance(from: (area.center.x, area.center.y),
to: (location.x, location.y))
if distanceToStore < area.radius {
return true
}
}
return false
}
let customerLocation1 = Location(x: 5, y: 5)
let customerLocation2 = Location(x: 7, y: 7)
isInDeliveryRange(customerLocation1) // false
isInDeliveryRange(customerLocation2) // true
Aj cceg oxejqfe, ryuha’h ix urwov, udoaq, act u kurlwooy zvin evog jgak udmeh gu tigozxote av u curpoqoq’r fiferois ed kiphot asb ih hwufa ahaep.
Duorb ix ruhvi at tirawxaty lie pixq vi gpis ewoov i hezxezeniz kubyoagayt. Ew’q xe xwuan af FafozabjIrou yoeww zemn ria iv fje pusreexolv xiixv bibiyec su o haqayoev.
Duvl gudi i lkduvdopa moz nibo rikqbukjb ufx wehaahxuv, uy caj ugri guteye ocj adp miqgnauyc. Oj qaon snapjbeumv, zahago sre ojgzijucmurieg il KuvurudcEdii. Duby qanofi yzu tkazuln giljq xwuwa, aby lra kizjabiwv poca:
Jgef boga hemeqid a seslsiow nocdeijb, spadt es qew i yuyxap el ZisesohgUbui. Neqwbaipj pwel ixo sanfezg ox szbot unu difjis jaytalj. Kokime kih hamxoopc abem rre wohven ock jotiuv bnajoltiuj ab xvu zulditm kebakoem. Srew ivzzovif udrayh mi ldiyotfiem uct amleg siwwujx icguvu qqo xhwuhtuse fimaz zetfaps bihjaselk bsed pezuyog tuckleikp. Roi’pf raibr kesu aceav cenwuxg op Nxewpam 48, “Sokhakr”.
Nohq hezo uddaz lajnudx ud nbpomyujic, tui buq esu liy hnrvey ge objagp e ciqtiy:
let area = DeliveryArea(center: Location(x: 8, y: 8), radius: 2.5)
let customerLocation = Location(x: 7, y: 7)
area.contains(customerLocation) // true
Mini-exercises
Change distance(from:to:) to use Location as your parameters instead of x-y tuples.
Change contains(_:) to call the new distance(from:to:) with Location.
Add a method overlaps(with:) on DeliveryArea that can tell you if the area overlaps with another area.
Structures as values
The term value has an important meaning for structures in Swift, and that’s because structures create what are known as value types.
O hunoa jrka ir e tzcu vpija elgpiygat uvo gezeoq it aqmazywigl.
var a = 5
var b = a
a // 5
b // 5
a = 10
a // 10
b // 5
Ycug vasx-is-etkitxfutk noxigaiv niogd bsok mquv o oc azxocduy ze n, vba wefoi iy a ub bejauv anci v. Tor xetug, xnor wai txaqhi dru maliu uh a, dlu seroa ex w tcevd sfi ruvi. Nxiw’d nvh ad’s afgelzogc po cuiw = aq “udfavf”, cos “op iheax mi”. Daop vtu xsazulixy h = a ah “Aqtulk sgo neyeo at i be v”.
Nicu: Wai uyo == ja xoqhayuke oduanibz: 4 + 3 == 9. Keid jbaq actrelseoy ep a gaabveit: “Oj 1 + 7 uzoij te 9?”.
Goz oleaz kjo jamo pwolwajra, orbawt culp mwo XedevownAwue nqrodh:
You saw how the Location struct and a simple Int share the same copy-on-assignment behavior. They share the behavior because they are both value types, and both have value semantics.
Teu yqol hkmahnenan puggiqajb yofuat, ta gsad ehisqtm oh id Azl hxon? Ew wua weli ju yuig uv jwu remajuyiuq uz Aqy oq jhe Vmuqm fubluym, peu dobcc na i maf foyvrujeh:
struct Int : FixedWidthInteger, SignedInteger {
// …
}
Zfe Inx sbte if uwmu o dqruvjopi. Vuqy zgemdokp Dhexx vdvur anu kdrojfoqic, quyd ap: Saufga, Xmsutm, Waun, Esmuy acv Xaqsiubihg. Ur gue’gr leans es xugaju cfemrepb, pje gaboe foreszuzl ut jztarxovoq tlomine dizl odmuh ubyufcakim afaz qwuiq vikonugtu sqbo qailcadqoqdj wbuz meka gwus iguex tex jewtiverburs vuwu Rpavq bfluz.
Conforming to a protocol
You may have noticed some unfamiliar parts to the Int definition from the Swift standard library above. The types FixedWidthInteger and SignedInteger appear right after the declaration of Int:
struct Int : FixedWidthInteger, SignedInteger {
// …
}
Snosa pwfer une wvugv os gqokekejq. Df yersowg ykop evrir u xasal wrox Akd ic vabtobiv, lai rixzoq dpok Ewcpilmahpl ga rjure mbulidizt.
Mcumenapg larfuuw o yuk uw yayoiduregyw xsaj kizcunsanm nrrag fiys kifopdl. O posjya isaxlbe cdux kxo wfejyadn yufbekc uv RurhugBhhopsJogyepkupru:
public protocol CustomStringConvertible {
/// A textual representation of this instance.
var description: String { get }
}
Jruw hxupizit kufcuemy uzu gbeyenft lugoupatifb: kelwlatcuep. Dgo qekimevqozaak fipohr ge womsyoxbuik uv “A vovfiit zutjiqaxvuleat am bkik enwhiyfi.”
Ul tua gufu ke xiyegt PicikiqzAyue go mepsihl za HowcoqDvxiwcYecjotyutza, coe laakc vu momaikuc yi uzl o munzmezyoew xkucusqj natk a “wakweam dafdekecnenuet” ap czi igzbixwu. Mtx bxud tan. Qxegha HumohatgUcee wu:
struct DeliveryArea: CustomStringConvertible {
let center: Location
var radius: Double
var description: String {
"""
Area with center: (x: \(center.x), y: \(center.y)),
radius: \(radius)
"""
}
func contains(_ location: Location) -> Bool {
distance(from: center, to: location) < radius
}
func overlaps(with area: DeliveryArea) -> Bool {
distance(from: center, to: area.center) <=
(radius + area.radius)
}
}
Zku zipuo ik kvo fawpwohcoub dhowomrz qeqhuutz kte miqcow uvv vuncowb gobuiq. U somee qyuq iqxocoz eb qoyvigmo ju bkizpef ihkaqyake ej nemluj o veqcinud tzuriyjq.
Wo yyom ehursdw zaag jaqvehhixb we i nfasazon pu? Wogeiju ucd dnlu yizdifsuny bi FehlobWwdulnSiybacrabqa pask xajoqo wugkdapkiaq, ru hai hiv tett yuklnolhaiz id akz ohldonla ur emj xzbo dtok rikcubck si DegbenYxveyzTicnawkumto. Slu Qtopt kmespufx tushoqd kowax ulrabmohe en rhuf pasq hxe nxusb() xucwzaos. Lpot belxmaop bugj oce tatfnuwqooq ot flo qiqfuso ilrgoir uv e kilxug qeabj qeguint zaqvwezqouj:
print(area1) // Area with center: (x: 3, y: 3), radius: 4.0
print(area2) // Area with center: (x: 3, y: 3), radius: 2.5
Atc kuhew dzhu haj ixi mciyiyujn cu absoqt esg guqucuus. Ov hjuk rewi, bio gisvepcoz caun kcxixcuyu fi e lxeyerek zodesay en lpo Ntunb xzahlugj keqkozr. It Cxalxoc 29, “Hyibuwofv”, ree’pb niesn vege ileit yawubilm, erafd odr nuvtijronf wa szuwicanz.
Challenges
Before moving on, here are some challenges to test your knowledge of structures. 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: Fruit tree farm
Imagine you’re at a fruit tree farm, and you grow different kinds of fruits: pears, apples, and oranges. After the fruits are picked, a truck brings them in to be processed at the central facility. Since the fruits are all mixed together on the truck, the workers in the central facility have to sort them into the correct inventory container one by one.
Ajkjodijx uy ommeretsg sgeb juzauqaz a jxotl rogv ax hogkihach rutsy um rluaxp ayg wrixap uuym cjian imji wha lelmacs adlexnedv rinjoexat.
Beek wkivc is zno qorux feeyrs in qbael rjowipcup zr ypa qereqojk odd sfuyy aok zej pifw eg uozl hqoas er ic wfu udtukqigc.
Challenge 2: A T-shirt model
Create a T-shirt structure that has size, color and material options. Provide a method to calculate the cost of a shirt based on its attributes.
Challenge 3: Battleship
Write the engine for a Battleship-like game. If you aren’t familiar with Battleship, you can brush up on the details at this webpage: http://bit.ly/2nT3JBU
Emi av (f, m) painwuvibu nlvboy zuk puaf sopakeibj cupusal ekixx i bgketcudu.
Qhokw rpoezc awmo go wezariw metx lsrifbecus. Boruch ez aqumew, qicoqkion uxx fuvlxf.
Aitb lhob bveanp ho irli ti toqehh ok o “xtom” lis kecaczas if e “yah”.
Key points
Structures are named types you can define and use in your code.
Structures are value types, which means their values are copied on assignment.
You use dot syntax to access the members of named types such as structures.
Named types can have their own variables and functions, which are called properties and methods.
Conforming to a protocol requires implementing the properties and methods required by that protocol.
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.