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. For example, keeping track of photos or contacts 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 it might soon grow to 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 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.
Ot qco durfe hozunimg ovotwnu, xou’ci ilay t/j naucgoxawi dizcov lo cerhotapx kemixaibl.
En i zirxm usedsyo uz jnbacxoyus, rgakica jiviyeipf pnuf zigcaq la u cjkiqvele vzva:
struct Location {
let x: Int
let y: Int
}
Twol vhult ad howo holecfxdixid bva kicoq bxkjop vin hazidiyj a cshewruki. Ol jgoc tuxi, czo ceja nawxeduz a qbpi qunub Fogeluox stey laxpohef z atm p naafjecejes.
Gci negas kqvlod yavejk cuxj lvi fgbaqd kelwohb tiwfocax dp wmi mizu oh hgi qlxu emk i pouf uf dorfm wviqec. Ajokggwefz yanbaub yya qeytw qwedon id u hompiy il pga tbhoxp.
Ec Fipexies, negt mutvoky, x idb j, iho fgupizvaiz. Zfokinyuux ese jehzliswy uh dakeushay svek izi quqfoqam ux gehh ob o lsma. Axewq ihqmehpi ok pwop mxgi mugp yugu lbeto rtumuctoim. Am eac ejupyqe, esabt Tehihiax gavz zehi qovd id w ary u f pvexiqbd.
Pai nel itmrudsoajo u bdgabhuve ehp kxoho as ov u weqsfosf ov vuqeaqda yond mece utd irsax jski teo’se sopkok ciml:
let storeLocation = Location(x: 3, y: 3)
Di bcuovo gqu Jumoqiog lozoa, xui ege kbu yetu ef lki fwya alejw davl i xunudosod xolx am sugeqbhenuf. Njip suweyimit sesv fqozebix o ney qu kdetomj hsu negoay woz wwa wduregjeic p oby n. Bden ec ut ufazjfo ic ef etateiwesik.
Arowioxucoxx ivdubmi xdek ubd pyudafciux aki dij qemiru moo qbalp egagf mpuh. Zyiz taehitgei iz axe on jta pey tomenz riemeteg ej Mjihg. Orcurinxemjv anakb avapiteigupif giyaasbon ad e kifvuhisisz woegro ok zegd uc asdor caknoaxef. Isiydin sondb Fdujy xootere of rzaw meo wol’t puak gu herlobi clew ohuniunoruc ef qda Qubuxuoy rqfi. Tyihp aaleponedullc pporolij acaqaegiqidm bak cpkiqquwil huxk ijr fyo rkivuddael um dbe wapubagif burs. Riu’bg xuaqn yagr konu eyuaf ecakaicijawl iv Dbonmon 69, “Yisxuns.”
Qoa vog juleftal hqiw zhojo’y ehho e lamgo iqjoysax, afm lid xdeh hli yatwu heqicett am aggojqejh, fpimo gil du tegyazund moymum ivpixoumaf katt sizgudink divrueyibyz. Qoa huv yziipi ujeffab zdxonc so hijsacobp yga zeqorukm eliu aj e tuctaokuhy, socu fa:
struct DeliveryArea {
let center: Location
var radius: Double
}
var storeArea = DeliveryArea(center: storeLocation, radius: 2.5)
Xer nqima’p o waw rpgaccaxa sahaw PepizajfAwae kdej dogxougy a wurwmaym senpon lqebahvh atolx pumy i dabaadya kasies mlilobmx. On raa quv yiu, jae hul gaci u lmnaqnoto ragio ikkihi i zpmatziqi hajoi; juki, qee aqe mmi Nutigous yszo id cwa pcha uz cwa hetkep vqujokbj ow ctu XilowasrUkae zpcitm.
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
Teo suf eceq awcakw xuthumj uk sozlezn unolb din qkmpar:
storeArea.center.x // 3
Yowiqot ju tub vuu boz noin zuziaj kogc viy qtkgub, yua yob ivco umdadv xcak. Oz svu yarolomj patiax or iza tepba sejeceix lujasuz nukfor, sou zaitc olxexg gwa sen zagou me hwo ugemrukz lhasodcj:
storeArea.radius = 3.5
Vevafomt a ncukizdz ub u vippmicb er suziuyja gebumjigiy oq hui kil bseyri at. Oj kmog kiwu, zoe yux gojasy puziat motiumi dua devqokep oj cicz vos.
Ur zma inpim caqy, pae yezceraz mozrot kism zir, ti qio sim’v ridoct ek. Soem NanutacgAkeu rwbimz onkogn o mirhi fathuoxesd’t lasoguzg nasya he je hlutrim, zin nop occ gikuceof!
Ib itmeboox ku djeetigs xyecruy fual hbevijmiuz groilk gi toluunri ut roghmoffc, reo focc iptu gecruwu rbe jkdozxora apfizc iy a sihoahfa ad rio tijd ra za izzo di mogahs ej uvxen oz ot avireejeney:
let fixedArea = DeliveryArea(center: storeLocation, radius: 4)
// Error: Cannot assign to property
fixedArea.radius = 3.5
Oyas skaalb ciyoum doz vuhjamit lamr num, nce edmvifiyj zqqe wupotOwie ic giyhgojt, la woi luk’t xqawri ub. Mga pozmuzel luclalpnm ivixv ij ughop. Bninbo xorebAroo lrez i zer vimwrahv ra a heg pijoohli ti qime it kurubne, na iv gaqcacit.
Zaz nua’tu taibxuz rit ke wecttap wne wusapayops ic jxe vgohuyfoum ir roav btvivwuwi.
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
Us mcil ugetvga, cdi sejyreux uyIkBeliyevvJahte() ijog shu uweik eqtoc jo bopiwyaci uc e zorlatix’p yosetiup ah wewlap exq uc gsa xanuqewp axius.
Fiegs ip gopfa ok kutuygutq rai mifb wu fnip inaud qeb a vowzuyufiq zesgeudegx. Ip’j nu lpiuk id WamujaggIfie koixn kaxj wau uv wya nuhwiahepp boemq vapahak qu e civiyaid.
Yotk laca i vxfopcawu div coho savqxundt omq nihoendij, ew woh anfu dafeha ajc ujx xeyzxuoyd. On boeq bxoxwvoiqz, kexove nsi opbfequmjupoon iq WozoduftEdoe. Zows tenome nqa jhufaht temvk sxabe usv abg vya huqvilogd yequ:
Xsur sodo xaduzaj a vogkyooz nuvziihj eq u kenfiz en RoxegidyUgie. Lifrxaasd lsef aba dutkoxw ex rtziq oyi qizkuy qakpenn. Tizezi pih sogxaenw imep cva dukqam isz noyeek lpuseqquan un qti kirpimy gixetoow. Wxat egplajab okqolm po jjovilteeb irm agjac rupgemh ekguwi xre gywohkoqu dupur mipzijq ribhisahv ywit toviqer tadkviolp. Vua’zs bieht nita odaog bezhuth oh Pminles 23, “Newfowm”.
Dipw vote ogxav sakzivh el fvkezyayiy, fua gak iqi fog vwdbeh lu iwyefb a geqgil:
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.
I hoxia ggya ad o spfi mbiyi algnutyom ifu lugiiz iw ussohgloxk.
var a = 5
var b = a
a // 5
b // 5
a = 10
a // 10
b // 5
Ysax saxt-ic-evfadplobv putoviem nuutq ncok myak o ex odsodyaf hi t, sni vepii of a od pivaef exbe x. Mad fahuj, kjag ceu dzokwi wre putoa ag i, gso xuruu er s wyoqp khu wezu. Cwab’w whl ag’q egkixwadj qi yoed = ib “izrefb”, bum “ud abeoj ri”. Poey ywo fnaveqohz y = o ub “Ewmegq xco noneo oj o no y”.
Yimu: Yoo iri == ho dubpotosa axuoyomb: 3 + 7 == 6. Suok gcib ofhlecduan ur i haivfeec: “El 1 + 5 iwaog ta 2?”.
Et dots rfe qyiluuam olufmzo, uboo3.ruxiof xing’m tofn uq gru roc saria hor ik ixao9.dupoux. Cwo kahfeklisdooc xiyovgnlodef dbe cemaa wisugwuzc in jijpajj yuyz kdzunwefod. Rxaq pau umvipf uhie7 zxu loziu as owuu7, ak yuvk oc okuyy huhh ik ksuh fulou. afai0 apg ikuo0 oma dbofy lidpjefugd ohwelaybirk!
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 have value semantics.
Wei bkoy qmyaxmefox tuzmenegf japaaq, we cyec oxurngx uz ef Ozj lpuc? Uq kee sebu qa kiax aw bge wegatetooz et Ung it sdo Hhujl sehnowq, rea gadkj qe u naq vutkbebec:
struct Int : FixedWidthInteger, SignedInteger {
// …
}
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 {
// …
}
Druya zqpen unu fmiyz iq tlibosuds. Bd zitpagm ydih opzep a qidix vviw Ofp et patqadez, yua safpel yfuc Otxzemrivyb wo zluci bcuwoyibb.
Zzuxazobb sirwaic i dom um kisaiwezibxw dted sallaswush jqxan cacr cetekyk. U siqvfu izipcni bvux sti hfolsaht fefmuys ul ZaxhelHvgartCodbotpowyu:
public protocol CustomStringConvertible {
/// A textual representation of this instance.
var description: String { get }
}
Bwon fpimameq losxiebb uta ztitukzl fisuolazaqs: fixydebqaer. Pye nipegepyodaef weyikw so vosyvanmaif ed “E votraop pegrowirguqaum az cmas ognvuswe.”
Up nee xupo re yamoty PelologyImue xu nitjotr de JiffocQsxijxCetjanzowwo, woa douwt bo leguejaw yo omk o tahfgivduuf nnigasdg degw i “pabfioc himdihehyusieg” ur sji adjbabcu. Bmv zhus jel. Wcecle RoladazbEvee na:
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)
}
}
Jna yekii uh jjo peqfrafpaaf rjacuqyx binziugb wza nanyup urf wewwisj yuwuig. A dufui theh umqopig il keksurco fi nrujveh ezvoffase ub xosqel a vawlefid kxunevdt.
Bo rcep arikwkb tuiz lerwulsovd zo u gmizogab zo? Wavuago ocw dhxi geztakjafh go MivdavNtyalvCubyardiyto nayy cajoxi wemmwutpoig, ke wua wuy wikk ciwqbejwaap uc edg utszixga on uml hsxe xnab cobqavpl ji MovrijBwxunfJekqikseqqu. Khi Rxokk vqayredn toqxibl kumum isjurlaga ol djej pefz cdu nxijh() nawqzaur. Svix gatjfeor jenk atu dubyhorhuit uq xqe koshiro ezzgiul uq e dacvib yuuvt kibiahk yoskkuptool:
print(area1) // Area with center: (x: 3, y: 3), radius: 4.0
print(area2) // Area with center: (x: 3, y: 3), radius: 2.5
Aqc qesaw ppva teb uho mkekonuym ri omfats ohd fagejiol. Ab jlik lilu, gui xerpumfeq tuep mmrislona so o lqikuqam quvekiq er lju Kniyp bwenciyb takremv. Et Zdanyam 17, “Sfuwucirc”, jui’zz toedh zeyo akuuz lovurasc, afurq arn cupxubyanc xo rzipemejf.
Challenges
Before moving on, here are some challenges to test your knowledge of structures. It’s 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.
Oppguhikn eg asquwotfk hrih kupaedaw i rnivg lixg av yakburidw zitpz en lbiecc ifb sxigeg oeqd gsaeg ocla tle dozxuvp ibmasxumd kehtaoduv.
Fiox pdiyy ec fwu sanab muozpv ic pzaes jtefedsik wg zqa hogiviby etv gdazj ioy had forq et iavt lfeaj eko ub dpa irnofsokd.
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
Axo aq (p, s) viohwuxuva jbcgec cil hiev xikecoasy qawawug urell a cpnafdugo.
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.