Swift From Scratch En introduksjon til klasser og strukturer

Hittil har vi dekket grunnleggende om Swift programmeringsspråket. Hvis du fulgte med, bør du nå ha en solid forståelse av variabler, konstanter, funksjoner og nedleggelser. Det er nå på tide å bruke det vi har lært og bruke den kunnskapen til Swifts objektorienterte strukturer.

For å forstå konseptene som er omtalt i denne opplæringen, er det viktig at du har en grunnleggende forståelse av objektorientert programmering. Hvis du ikke er kjent med klasser, objekter og metoder, anbefaler jeg deg først å lese om disse emnene før du fortsetter med denne opplæringen.

eBok: Objektorientert programmering med Swift

1. Introduksjon

I denne leksjonen skal vi utforske de grunnleggende byggeblokkene i objektorientert programmering i Swift, klasser og strukturer. I Swift, klasser og strukturer føler og oppfører seg veldig like, men det er en rekke sentrale forskjeller som du trenger å forstå for å unngå vanlige fallgruver.

I Mål-C er klasser og strukturer svært forskjellige. Dette er ikke sant for Swift. I Swift kan for eksempel både klasser og strukturer ha egenskaper og metoder. I motsetning til C-strukturer kan strukturer i Swift utvides, og de kan også overholde protokollene.

Det åpenbare spørsmålet er: "Hva er forskjellen mellom klasser og strukturer?" Vi vil besøke dette spørsmålet senere i denne opplæringen. La oss først undersøke hva en klasse ser ut i Swift.

2. Terminologi

Før vi begynner å jobbe med klasser og strukturer, vil jeg gjerne avklare noen vanlige bruksbetingelser i objektorientert programmering. Vilkårene klasser, objekter, og forekomster Forvirre ofte folk som er ny til objektorientert programmering. Derfor er det viktig at du vet hvordan Swift bruker disse vilkårene.

Objekter og forekomster

EN klasse er en blåkopi eller mal for en forekomst av den klassen. Begrepet "objekt" brukes ofte til å referere til en forekomst av en klasse. I Swift er klasser og strukturer imidlertid svært like, og det er derfor lettere og mindre forvirrende å bruke begrepet "forekomst" for både klasser og strukturer.

Metoder og funksjoner

Tidligere i denne serien jobbet vi med funksjoner. I sammenheng med klasser og strukturer refererer vi vanligvis til funksjoner som metoder. Metoder er med andre ord funksjoner som tilhører en bestemt klasse eller struktur. I sammenheng med klasser og strukturer kan du bruke begge termer om hverandre, siden hver metode er en funksjon.

3. Definere en klasse

La oss få føttene våte og definere en klasse. Brann opp Xcode og opprett en ny lekeplass. Fjern innholdet på lekeplassen og legg til følgende klasses Definisjon.

klasse person 

De klasse Søkeordet indikerer at vi definerer en klasse som heter Person. Gjennomføringen av klassen er pakket inn i et par krøllete braces. Selv om Person klassen er ikke veldig nyttig i sin nåværende form, det er en skikkelig, funksjonell Swift klasse.

Eiendommer

Som i de fleste andre objektorienterte programmeringsspråk kan en klasse ha egenskaper og metoder. I det oppdaterte eksemplet nedenfor definerer vi tre egenskaper:

  • fornavn, en variabel egenskap av typen string?
  • etternavn, en variabel egenskap av typen string?
  • fødested: en konstant egenskap av type string
klasse Person var firstName: String? var lastnavn: streng? la birthPlace = "Belgium"

Som eksemplet illustrerer, er definisjon av egenskaper i en klassdefinisjon likt å definere vanlige variabler og konstanter. Vi bruker Var søkeord for å definere en variabel egenskap og la søkeord for å definere en fast eiendom.

Ovenstående egenskaper er også kjent som lagrede egenskaper. Senere i denne serien lærer vi om beregnede egenskaper. Som navnet antyder, er lagrede egenskaper egenskaper som er lagret av klasseeksemplet. De ligner egenskaper i Objective-C.

Det er viktig å merke seg at hver lagret eiendom må ha en verdi etter initialisering eller defineres som en valgfri type. I eksemplet ovenfor gir vi fødested eiendom en innledende verdi på "Belgia". Dette forteller Swift at fødestedet er av typen string. Senere i denne artikkelen tar vi en nærmere titt på initialiseringen og undersøker hvordan det knytter seg til initialisering av egenskaper.

Selv om vi definerte fødested eiendom som en konstant, er det mulig å endre verdien under initialiseringen av a Person forekomst. Når forekomsten er initialisert, vil fødested Eiendom kan ikke lenger endres siden vi definerte eiendommen som en fast eiendom med la søkeord.

metoder

Vi kan legge til oppførsel eller funksjonalitet i en klasse gjennom funksjoner eller metoder. I mange programmeringsspråk, metode brukes i stedet for funksjon i sammenheng med klasser og forekomster. Definere en metode er nesten identisk med å definere en funksjon. I det neste eksemplet definerer vi fullt navn() metode i Person klasse.

klasse Person var firstName: String? var lastnavn: streng? la birthPlace = "Belgium" func fullName () -> String var deler: [String] = [] hvis la firstName = self.firstName parts + = [firstName] hvis la lastName = self.lastName parts + = [ lastName] returnere parts.joined (separator: "")

Metoden fullt navn() er nestet i klassen definisjonen. Den aksepterer ingen parametere og returnerer a string. Gjennomføringen av fullt navn() metoden er enkel. Gjennom valgfri binding, som vi diskuterte tidligere i denne serien, får vi tilgang til verdiene som er lagret i fornavn og etternavn eiendommer.

Vi lagrer for- og etternavnet til Person forekomme i en matrise og delta i delene med et mellomrom. Årsaken til denne litt vanskelige implementeringen bør være åpenbar: for- og etternavnet kan være tomt, derfor er begge egenskapene av typen string?.

oppretting

Vi har definert en klasse med noen få egenskaper og en metode. Hvordan lager vi en forekomst av Person klasse? Hvis du er kjent med Objective-C, vil du elske konsistensen til følgende utdrag.

la john = Person ()

Instantiating en forekomst av en klasse er veldig lik å påkalle en funksjon. For å opprette en forekomst blir klassens navn etterfulgt av et par parenteser, og returverdien er tilordnet en konstant eller variabel.

I vårt eksempel, konstanten john peker nå på en forekomst av Person klasse. Betyr dette at vi ikke kan endre noen av dens egenskaper? Neste eksempel svarer på dette spørsmålet.

john.firstName = "John" john.lastName = "Doe" john.birthPlace = "France"

Vi kan få tilgang til egenskapene til en forekomst ved hjelp av punktsyntaxen. I eksemplet setter vi fornavn til "John", etternavn til "Doe", og fødested til "Frankrike". Før vi trekker noen konklusjoner basert på eksemplet ovenfor, må vi sjekke om eventuelle feil på lekeplassen.

Innstilling fornavn og etternavn ser ikke ut som noen problemer. Men tildele "Frankrike" til fødested Egenskapen resulterer i en feil. Forklaringen er enkel.

Selv om john er erklært som en konstant, som ikke hindrer oss fra å modifisere Person forekomst. Det er imidlertid en advarsel, men bare variable egenskaper kan endres etter initialisering av en forekomst. Egenskaper som er definert som konstant, kan ikke endres når en verdi er tildelt.

En konstant egenskap kan endres under initialisering av en forekomst. Mens fødested Eiendommen kan ikke endres en gang a Person Eksempel er opprettet, klassen ville ikke være veldig nyttig hvis vi bare kunne instantiere Person forekomster med en fødested for "Belgia". La oss lage Person klassen litt mer fleksibel.

initialisering

Initialisering er en fase i levetiden til en forekomst av en klasse eller struktur. Under initialisering forbereder vi forekomsten for bruk ved å fylle sine egenskaper med innledende verdier. Initialiseringen av en forekomst kan tilpasses ved å implementere en initialiserer, en spesiell type metode. La oss definere en initialiserer for Person klasse.

klasse Person var firstName: String? var lastnavn: streng? la birthPlace = "Belgium" init () birthPlace = "France" ...

Vi har definert en initialiserer, men vi løper inn i flere problemer. Ta en titt på feilen kompilatoren kaster på oss.

Ikke bare er initialisatoren meningsløs, kompilatoren advarer også oss om at vi ikke kan endre verdien av fødested eiendom siden den allerede har en innledende verdi. Vi kan løse feilen ved å fjerne initialverdien til fødested eiendom.

klasse Person var firstName: String? var lastnavn: streng? la birthPlace: String init () birthPlace = "France" ...

Merk at navnet på initialisatoren, i det(), er ikke på forhånd av func søkeord. I motsetning til initiativer i Objective-C returnerer en initialiserer i Swift ikke forekomsten som initialiseres.

En annen viktig detalj er hvordan vi setter inn fødested eiendom med en innledende verdi. Vi satte fødested eiendom ved å bruke eiendommens navn, men det er også fint å være mer eksplisitt som dette.

init () self.birthPlace = "France"

De selv- søkeord refererer til forekomsten som blir initialisert. Dette betyr at self.birthPlace refererer til fødested eiendom av forekomsten. Vi kan utelate selv-, som i det første eksemplet, fordi det ikke er forvirring om hvilken eiendom vi refererer til. Dette er ikke alltid tilfelle, skjønt. La meg forklare hva jeg mener.

parametere

Initialiseringen vi definerte er ikke veldig nyttig for øyeblikket, og det løser ikke problemet vi startet med: å kunne definere fødselsstedet til en person under initialisering. 

I mange situasjoner vil du sende initialverdier til initialisatoren for å tilpasse forekomsten du instanser. Dette er mulig ved å opprette en tilpasset initialiserer som aksepterer en eller flere argumenter. I det følgende eksempelet oppretter vi en tilpasset initialiserer som aksepterer ett argument, fødested, av type string.

init (birthPlace: String) self.birthPlace = birthPlace

To ting er verdt å peke på. Først må vi få tilgang til fødested eiendom gjennom self.birthPlace for å unngå tvetydighet siden det lokale parameternavnet er lik fødested. For det andre, selv om vi ikke har angitt et eksternt parameternavn, oppretter Swift som standard et eksternt parameternavn som er lik det lokale parameternavnet.

I det følgende eksemplet ordner vi en annen Person eksempel ved å påkalle den tilpassede initialiseringen vi nettopp har definert.

la maxime = Person (birthPlace: "France") print (maxime.birthPlace)

Ved å overføre en verdi for fødested parameter til initialisatoren, kan vi tilordne en tilpasset verdi til konstanten fødested eiendom under initialisering.

Flere initiativer

Som i mål-C kan en klasse eller struktur ha flere initiativer. I det følgende eksempel oppretter vi to Person forekomster. I første linje bruker vi standardinitialiseringen. I den andre linjen bruker vi den tilpassede initialiseringen vi definerte tidligere.

la p1 = Person () la p2 = Person (fødested: "Frankrike")

4. Definere en struktur

Strukturer er overraskende lik klasser, men det er noen viktige forskjeller. La oss begynne med å definere en grunnleggende struktur.

struct lommebok var dollar: Int var cents: Int

Ved første øyekast er den eneste forskjellen bruken av struct søkeord i stedet for klasse søkeord. Eksemplet viser også oss en alternativ tilnærming til å levere innledende verdier til egenskaper. I stedet for å sette en innledende verdi for hver eiendom, kan vi gi egenskaper en startverdi i initialiseringen av strukturen. Swift vil ikke kaste en feil, fordi den også inspiserer initialisatoren for å bestemme den opprinnelige verdien og typen av hver eiendom.

5. Klasser og strukturer

Du kan begynne å lure på hva forskjellen er mellom klasser og strukturer. Ved første øyekast ser de ut identiske i form og funksjon, med unntak av klasse og struct søkeord. Det er imidlertid en rekke viktige forskjeller.

Arv

Klasser støtter arv, mens strukturer ikke gjør det. Følgende eksempel illustrerer dette. Arvsmønsteret er uunnværlig i objektorientert programmering, og i Swift er det en viktig forskjell mellom klasser og strukturer.

klasse Person var firstName: String? var lastnavn: streng? la birthPlace: String init (birthPlace: String) self.birthPlace = birthPlace klasse Student: Person var skole: String?  la student = Student (birthPlace: "France")

I eksempelet ovenfor er det Person klassen er forelder eller superklasse av Student klasse. Dette betyr at Student Klassen arver egenskapene og oppførselen til Person klasse. Den siste linjen illustrerer dette. Vi initialiserer en Student eksempel ved å påkalle den tilpassede initialisereren definert i Person klasse.

Kopiering og referanse

Følgende konsept er trolig det viktigste konseptet i Swift du lærer i dag, forskjellen mellom verdi typer og referansetyper. Strukturer er verdi typer, noe som betyr at de er bestått etter verdi. Et eksempel illustrerer dette konseptet best.

struktur Punkt var x: Int var y: Int init (x: Int, y: Int) self.x = x self.y = y var punkt1 = Punkt (x: 0, y: 0) var punkt2 = punkt1 punkt1.x = 10 utskrift (punkt1.x) // 10 utskrift (punkt2.x) // 0

Vi definerer en struktur, Punkt, å inkapslere dataene for å lagre en koordinat i et todimensjonalt rom. Vi instanser point1 med x lik 0 og y lik 0. Vi tildeler point1 til poeng2 og sett x koordinat av point1 til 10. Hvis vi sender ut x koordinere begge punkter, oppdager vi at de ikke er like.

Strukturer er bestått av verdi, mens klasser er bestått ved referanse. Hvis du planlegger å fortsette å jobbe med Swift, må du forstå forrige setning. Når vi tildelte point1 til poeng2, Swift opprettet en kopi av point1 og tilordnet den til poeng2. Med andre ord, point1 og poeng2 hvert punkt til en annen forekomst av Punkt struktur.

La oss nå gjenta denne øvelsen med Person klasse. I det følgende eksemplet ordner vi en Person Installer, sett dens egenskaper, tilordne menneske1 til person2, og oppdatere fornavn tilhører menneske1. For å se hva som går med referansemidler for klasser, utfører vi verdien av fornavn eiendom av begge deler Person forekomster.

var person1 = Person (birthPlace: "Belgium") person1.firstName = "Jane" person1.lastName = "Gjør" var person2 = person1 person1.firstName = "Janine" print (person1.firstName!) // Janine print (person2. fornavn!) // Janine

Eksemplet viser at klasser er referansetyper. Dette betyr at menneske1 og person2 referer til eller referer til det samme Person forekomst. Ved tildeling menneske1 til person2, Swift lager ikke en kopi av menneske1. De person2 variabel punkter til det samme Person forekomst menneske1 peker på. Endre fornavn tilhører menneske1 påvirker også fornavn tilhører person2, fordi de refererer til det samme Person forekomst.

Som jeg nevnte flere ganger i denne artikkelen, er klasser og strukturer veldig like. Hva skiller klasser og strukturer er svært viktig. Hvis de ovennevnte begrepene ikke er klare, oppfordrer jeg deg til å lese artikkelen en gang til for å la de konseptene vi dekket synke inn.

Konklusjon

I denne delen av Swift From Scratch har vi begynt å utforske grunnleggende om objektorientert programmering i Swift. Klasser og strukturer er de grunnleggende byggeblokkene i de fleste Swift-prosjekter, og vi lærer mer om dem i de neste leksjonene i denne serien.

I neste leksjon fortsetter vi utforskningen av klasser og strukturer ved å se nærmere på eiendommer og arv.

Hvis du vil lære hvordan du bruker Swift 3 til å kode sanntidsprogrammer, sjekk ut kurset ditt Opprett IOS Apps With Swift 3. Enten du er ny i iOS app-utvikling eller ønsker å skifte bryteren fra Objective-C, dette kurset vil komme i gang med Swift for app utvikling.