I den første artikkelen i denne introduksjonsserien om Swift snakket vi om Swifts filosofi, tok en første titt på sin syntaks og fremhevet noen viktige forskjeller med Objective-C. I denne artikkelen fortsetter vi utforskningen av Swifts syntaks. Du vil også lære om optionsals og se hvordan minnehåndtering fungerer i Swift.
Hvis setningene er like i Swift og Objective-C, med unntak av to subtile forskjeller:
Disse handler om de eneste forskjellene med om setninger i Mål-C.
Som vi så i den første artikkelen, inkluderer Swift to rekkevidde operatører ... <
og ...
å angi en rekke verdier. Disse to operatørene er Half-closed Range Operator og lukket operatør.
Et halvt lukket område, for eksempel 1… <5
, representerer verdiene 1, 2, 3 og 4, unntatt 5. Et lukket område, for eksempel 1 ... 5
, representerer verdiene 1, 2, 3, 4 og inkluderer 5.
Rangene kan brukes i til
løkker, matrise
abonnement, og til og med i bytte om
uttalelser. Ta en titt på følgende eksempler.
// for loop eksempel for jeg i 1 ... <10 // iterates from 1 to 9
// array subscript eksempel la noenArray = ["apple", "pair", "fersken", "vannmelon", "jordbær"] for frukt i someArray [2 ... <4] println(fruit) // outputs: peach and watermelon
// bytt eksempelbryter noenInt tilfelle 0: // gjør noe med 0 tilfelle 1 ... <5: // do something with 1,2,3,4 case 5… 10: // do something with 5,6,7,8,9,10 default: // everything else
Switch-setninger er kraftigere i Swift enn de er i Objective-C. I mål-C må resultatet av uttrykket av en bryteretning være av typen heltall, og verdiene for hver tilfelleoppgave skal være et konstant eller konstant uttrykk. Dette er ikke sant i Swift. I Swift kan saksoppgavene være av noe slag, inkludert intervaller.
I Swift har bryteren nr gå i stykker
uttalelser og det faller ikke automatisk fra ett tilfelle til et annet. Når du skriver en bryteretning, må du være oppmerksom på at alle forhold håndteres av saksoppgavene, hvis du ikke gjør det, vil det føre til en kompilatorfeil. En sikker måte å dekke alle forhold på er å inkludere a misligholde
saksoppgave.
Her er et eksempel på a bytte om
uttalelse med string
saker:
la grønnsak = "rød pepper" bryter grønnsak sak "selleri": la vegetabilskComment = "Legg til noen rosiner og lage maur på en logg." tilfelle "agurk", "watercress": la vegetabilskComment = "Det ville lage en god te sandwich." standard: la vegetableComment = "Alt smaker godt i suppe."
I Swift faller ikke saksdeklarasjoner som standard. Dette var en bevisst designbeslutning for å unngå vanlige feil. Hvis et bestemt tilfelle trenger å falle gjennom, kan du bruke faller gjennom
søkeord for å indikere dette til kompilatoren.
bytt noenInt case 0: // gjør noe med 0 tilfelle 1: // gjør noe med 1 tilfelle 2: // gjør noe med 2 fallthrough standard: // gjør noe for alt annet // tilfelle 2 vil falle gjennom til standard sak
Det stopper ikke her. Swift legger til to andre funksjoner for å bytte, verdi bindinger og hvor klausul. Verdibinding brukes med tilfelle la
søkeord for å binde en konstant med matchende tilfelle. Var-klausulen legger til en ekstra betingelse for saksoppstillingen ved hjelp av hvor
søkeord.
Disse to konseptene er bedre forklart med eksempler. Følgende kodeblokk viser hvordan verdi bindende virker.
la noenPoint = (xaxis: 2, yaxis: 0) bytte somePoint tilfelle (la x, 0): println ("på x-aksen med en x-verdi på \ (x)") tilfelle (0, la y) println ("på y-aksen med ay verdi av \ (y)") tilfelle la (x, y): println ("et annet sted på (\ (x), \ (y))")
Den første saken uttalelse, tilfelle (la x, 0)
, vil matche verdiene der y-aksen
er lik 0
og noen verdi for x-aksen
, og vi binder x-aksen
til konstanten x
å bli brukt i saken setningen.
Her er et eksempel på hvor klausulen er i aktion.
la grønnsak = "rød pepper" bytt vegetabilsk tilfelle "selleri": println ("Legg til noen rosiner og lage maur på en logg.") tilfelle la x hvor x.hasSuffix ("pepper"): println ("Jeg er allergisk til \ (x) ") standard: println (" Alt smaker godt i suppe. ") // utganger: Jeg er allergisk mot rød pepper
Definisjon av funksjoner og nedleggelser er enkelt i Swift. Mål-C-utviklere kjenner dem bedre som funksjoner og blokker.
I Swift kan funksjonsparametere ha standardverdier, noe som minner om skriptspråk, som PHP og Ruby.
Syntaxen for funksjoner er som følger:
func-funksjonnavn (parameternavn: Type = DefaultValue) -> returnType [...] returnertype;
Å skrive en si hei
funksjon som tar en parameter Navn
av type string
og returnerer a bool
når vellykket skriver vi følgende:
func sayHello (navn: String) -> Bool println ("hei \ (navn)"); returnere sant; sayHello ("World") // utgang // hallo verden
For å passere en standardverdi for Navn
parameteren, vil funksjonens implementering se ut som følger:
func sayHello (navn: String = "World") -> Bool println ("hei \ (navn)"); returnere sant; sayHello () // output // hei World sayHello ("Mike") // output // hei mike
En funksjon som er helt fraværende i Objective-C er tupler. I Swift kan funksjoner returnere flere verdier i form av en tuple. Tuples blir behandlet som en enkelt variabel, noe som betyr at du kan passere den rundt akkurat som en variabel.
Tuples er veldig enkle å bruke. Faktisk har vi allerede jobbet med tuples i forrige artikkel da vi oppnådde en ordbok. I neste kodestykke er nøkkel / verdi-paret en tuple.
for (nøkkel, verdi) i noenDictionary println ("Key \ (key) har verdi \ (verdi)"
Hvordan brukes tuples og hvordan drar du nytte av dem? La oss ta en titt på et annet eksempel. La oss endre det ovenfor si hei
funksjon for å returnere en boolesk når vellykket, så vel som den resulterende meldingen. Vi gjør dette ved å returnere en tuple, (Bool, String)
. Den oppdaterte si hei
funksjonen ser slik ut:
func sayHello (navn: String = "World") -> (Bool, String) let greeting = "hei \ (navn)" returnere (sann, hilsen); la (vellykket hilsen) = sayHello () println ("sayHello returnerte suksess: \ (suksess) med hilsen: \ (hilsen)"); // utgang // sayHello returnerte suksess: 1 med hilsen: hallo verden
Tuples har vært på ønskeliste av mange Objective-C programmerere i lang tid.
En annen kul funksjon av tuples er at vi kan nevne de returnerte variablene. Hvis vi går tilbake til forrige eksempel og gir navn til variablene i tupelen, får vi følgende:
func sayHello (navn: String = "World") -> (suksess: Bool, hilsen: String) let greeting = "hei \ (navn)" returnere (sann, hilsen); la status = sayHello () println ("sayHello returnerte suksess: \ (status.success) med hilsen: \ (status.greeting)"); // utgang // sayHello returnerte suksess: 1 med hilsen: hallo verden
Dette betyr at i stedet for å definere en separat konstant for hvert returelement av en tuple, kan vi få tilgang til de returnerte tuple-elementene ved hjelp av punktnotasjon som vist i eksemplet ovenfor, status.success
og status.greeting
.
Lukker i Swift er de samme som blokkene i Objective-C. De kan defineres inline, bestått som en parameter, eller returneres av funksjoner. Vi bruker dem akkurat som vi ville bruke blokker i Objective-C.
Det er også enkelt å definere nedleggelser. Faktisk er en funksjon et spesielt tilfelle av nedleggelser. Så det er ikke rart at definere en lukking ser mye ut som å definere en funksjon.
Lukk er en førsteklasses type, som betyr at de kan bestås og returneres av funksjoner som alle andre typer, for eksempel int
, string
, bool
, etc. Lukker er i hovedsak kodeblokker som kan kalles senere og har tilgang til omfanget der de ble definert.
Å lage en navnløs lukning er like enkelt som å pakke inn en blokk med koden i krøllete braces. Parametrene og returtypen til lukkingen er skilt fra lukkens kropp med i
søkeord.
La oss si at vi ønsker å definere et lukket som kommer tilbake ekte
hvis et tall er jevnt, så kan lukkingen se ut som:
la isEven = (nummer: Int) -> Bool i let mod = nummer% 2 retur (mod == 0)
De ISEVEN
lukking tar en int
som sin enparameter og returnerer a bool
. Typen av denne lukkingen er (nummer: Int) -> Bool
, eller (Int -> Bool)
for kort. Vi kan ringe ISEVEN
hvor som helst i vår kode akkurat som vi ville påkalle en kodeblokk i Objective-C.
For å passere en lukking av denne typen som en parameter av en funksjon, bruker vi lukkets type i funksjonens definisjon:
la isEven = (nummer: Int) -> Bool i let mod = tall% 2; returnere (mod == 0); func verifyIfEven (nummer: Int, verifier: (Int-> Bool)) -> Bool return verifier (nummer); verifyIfEven (12, erEven); // returnerer sant verifiseringIfEven (19, erEven); // returnerer false
I eksempelet ovenfor er det bekreft
parameteren til verifyIfEven
funksjon er et lukning som vi overfører til funksjonen.
Det er på tide å snakke om hjørnestenen i objektorientert programmering, klasser. Klasser, som nevnt tidligere, er definert i en enkelt implementeringsfil med en .fort forlengelse. Eiendomserklæringer og metoder er alle definert i den filen.
Vi lager en klasse med klasse
søkeord etterfulgt av klassens navn. Klassens implementering er innpakket i et par krøllete braces. Som i mål-C, er navngivningskonvensjonen for klasser å bruke øvre kamelveske for klassenavn.
klasse hotell // egenskaper // funksjoner
Å opprette en forekomst av Hotell
klasse vi skriver:
la h = Hotel ()
I Swift er det ikke nødvendig å ringe i det
på objekter som i det
kalles automatisk for oss.
Klassen arv følger det samme mønsteret som i Mål-C, et kolon skiller klassenavnet og det som er dets superklasse. I følgende eksempel, Hotell
arv fra BigHotel
klasse.
klassen BigHotel: Hotel
Som i mål-C bruker vi punktnotasjon for å få tilgang til objektets egenskaper. Imidlertid bruker Swift også punktnotasjonen til å påkalle klasse- og instansmetoder som du kan se nedenfor.
// Objektiv-C UIView * view = [[UIView alloc] init]; [self.view addSubview: view]; // Swift la vise = UIView () self.view.addSubview (se)
En annen forskjell med Objective-C er at Swift ikke skiller mellom instansvariabler (ivars) og egenskaper. En instansvariabel er en eiendom.
Deklarere en egenskap er akkurat som å definere en variabel eller en konstant, ved hjelp av Var
og la
søkeord. Den eneste forskjellen er konteksten der de er definert, det vil si konteksten til en klasse.
klasse hotell la rom = 10 var fullrom = 0
I eksemplet ovenfor, rom
er en uforanderlig verdi, en konstant, satt til 10
og fullRooms
er en variabel med en startverdi på 0
, som vi kan endre senere. Regelen er at egenskaper må initialiseres når de er erklært. Det eneste unntaket til denne regelen er valgmuligheter, som vi diskuterer om et øyeblikk.
Swift-språket definerer også beregnede egenskaper. Beregnede egenskaper er ikke noe annet enn fancy getters og setters som ikke lagrer en verdi. Som navnet indikerer, blir de beregnet eller evaluert på fluen.
Nedenfor er et eksempel på en beregnet eiendom. Jeg har endret rom
eiendom til a Var
for resten av disse eksemplene. Du vil finne ut hvorfor senere.
Klasse Hotel var rom = 10 var fullRooms = 0 var beskrivelse: String get return Hotellstørrelse: \ (rom) rom kapasitet: \ (fullRooms) / \ (rom) "
Fordi det beskrivelse
Eiendommen er skrivebeskyttet og har bare a komme tilbake
uttalelse, kan vi utelate få
søkeord og krøllete braces, og bare hold komme tilbake
uttalelse. Dette er shorthand, og det er det jeg skal bruke i resten av denne opplæringen.
Klasse Hotel var rom = 10 var fullRom = 0 var beskrivelse: String retur "Hotellstørrelse: \ (rom) rom kapasitet: \ (fullrom) / \ (rom)"
Vi kan også definere lese-skrive beregnede egenskaper. I vår klasse Hotell
, vi vil ha en emptyRooms
eiendom som får antall tomme rom på hotellet, men vi vil også oppdatere fullRooms
når vi setter emptyRooms
beregnet eiendom. Vi kan gjøre dette ved å bruke sett
søkeord som vist nedenfor.
Klasse Hotel var rom = 10 var fullRooms = 0 var beskrivelse: String retur "Hotellstørrelse: \ (rom) rom kapasitet: \ (fullRooms) / \ (rom)" var tomRommene: Int get return rooms - fullRooms set // newValue konstant er tilgjengelig her // som inneholder bestått verdi hvis (newValue < rooms) fullRooms = rooms - newValue else fullRooms = rooms let h = Hotel() h.emptyRooms = 3 h.description // Size of Hotel: 10 rooms capacity:7/10
I emptyRooms
setter, den nyVerdi
Konstant er overlevert til oss og representerer verdien som er overført til setteren. Det er også viktig å merke seg at beregnede egenskaper er alltid deklarert som variabler, ved hjelp av Var
søkeord, fordi deres beregnede verdi kan endres.
Vi har allerede dekket funksjoner tidligere i denne artikkelen. Metoder er ikke mer enn funksjoner som er knyttet til en type, for eksempel en klasse. I følgende eksempel implementerer vi en instansmetode, bookNumberOfRooms
, i Hotell
klasse vi opprettet tidligere.
Klasse Hotel var rom = 10 var fullRooms = 0 var beskrivelse: String retur "Hotellstørrelse: \ (rom) rom kapasitet: \ (fullRooms) / \ (rom)" var tomRommene: Int get return rooms - fullRooms set // newValue konstant er tilgjengelig her // som inneholder bestått verdi hvis (newValue < rooms) fullRooms = rooms - newValue else fullRooms = rooms func bookNumberOfRooms(room:Int = 1) -> Bool if (self.emptyRooms> rom) self.fullRooms ++; returnere true ellers return false la h = Hotel () h.emptyRooms = 7 h.description // Hotellstørrelse: 10 rom kapasitet: 3/10 h.bookNumberOfRooms (rom: 2) // returnerer sann h .description // Hotellstørrelse: 10 rom kapasitet: 5/10 h.bookNumberOfRoom () // returnerer sann h.description // Hotellstørrelse: 10 rom kapasitet: 6/10
Standardinitialiseringen for klasser er i det
. I i det
funksjon, setter vi innledningsverdiene til forekomsten som er opprettet.
For eksempel, hvis vi trenger en Hotell
subclass med 100 rom, så ville vi trenge en initializer å sette rom
eiendom til 100
. Husk at jeg tidligere har endret rom
fra å være en konstant til å være en variabel i Hotell
klasse. Årsaken er at vi ikke kan endre arvelige konstanter i en underklasse, bare arvelige variabler kan endres.
klasse BigHotel: Hotel init () super.init () rooms = 100 la bh = BigHotel () println (bh.description); // Størrelse på hotellet: 100 rom kapasitet: 0/100
Initialisatorer kan også ta parametere. Følgende eksempel viser hvordan dette virker.
klasse CustomHotel: Hotel init (størrelse: Int) super.init () rooms = size la c = CustomHotel (størrelse: 20) c.description // Hotellstørrelse: 20 rom kapasitet: 0/20
Dette er en av de kuleste tingene i Swift. I Swift kan en underklasse overstyre begge metoder og beregnede egenskaper. For å gjøre det bruker vi overstyring
søkeord. La oss overstyre beskrivelse
Beregnet eiendom i CustomHotel
klasse:
klasse CustomHotel: Hotel init (størrelse: Int) super.init () rooms = size overstyre var beskrivelse: String return super.description + "Howdy!" la c = CustomHotel (størrelse: 20) c.description // Størrelse på hotellet: 20 rom kapasitet: 0/20 Howdy!
Resultatet er det beskrivelse
returnerer resultatet av superklassens beskrivelse
metode med strengen "Howdy!"
lagt til det.
Hva er kult om overordnede metoder og beregnede egenskaper er overstyring
søkeord. Når kompilatoren ser overstyring
søkeord, det kontrollerer hvor klassens superklasse implementerer metoden som blir overstyrt. Kompilatoren kontrollerer også om egenskapene og metodene til en klasse er i konflikt med egenskaper eller metoder høyere opp i arvstreet.
Jeg vet ikke hvor mange ganger en skrivefeil i en overstyrt metode i Objective-C gjorde meg forbanne fordi koden ikke fungerte. I Swift vil kompilatoren fortelle deg nøyaktig hva som er galt i disse situasjonene.
Strukturer, definert med struct
søkeord, er kraftigere i Swift enn de er i C og Objective-C. I C definerer strukturer bare verdier og pekere. Swift structs er akkurat som C-strukturer, men de støtter også beregnede egenskaper og metoder.
Alt du kan gjøre med en klasse, kan du gjøre med en struktur, med to viktige forskjeller:
Her er noen få eksempler på strukturer i Swift:
struktur Rect var opprinnelse: Punkt var størrelse: Størrelse var område: Dobbel return size.width * size.height func erBiggerThanRect (r: Rect) -> Bool return (self.area> r.area) struct Point var x = 0 var y = 0 struct Størrelse var bredde = 0 var høyde = 0
Alternativer er et nytt konsept hvis du kommer fra Objective-C. De løser et problem vi alle møter som programmerere. Når vi får tilgang til en variabel hvis verdi vi ikke er sikre på, returnerer vi vanligvis en indikator, kjent som en sentinel, for å indikere at den returnerte verdien er en ikke-verdi. La meg illustrere dette med et eksempel fra Mål-C:
NSString * someString = @ "ABCDEF"; NSInteger pos = [someString rangeOfString: @ "B"]. Sted; // pos = 1
I eksemplet ovenfor prøver vi å finne posisjonen til @ "B"
i someString
. Hvis @ "B"
er funnet, er plasseringen eller posisjonen lagret i pos
. Men hva skjer hvis @ "B"
er ikke funnet i someString
?
Dokumentasjonen sier at rangeOfString:
returnerer en NSRange
med plassering
satt til NSNotFound
konstant. I tilfelle av rangeOfString:
, Sentinel er NSNotFound
. Sentineller brukes til å indikere at den returnerte verdien ikke er gyldig.
I kakao er det mange bruksområder av dette konseptet, men sentinelverdien skiller seg fra kontekst til kontekst, 0
, -1
, NULL
, NSIntegerMax
, INT_MAX
, Nil
, etc. Problemet med programmereren er at hun må huske hvilken sentinel som brukes i hvilken sammenheng. Hvis programmereren ikke er forsiktig, kan hun feile en gyldig verdi for en sentinel og omvendt. Swift løser dette problemet med valgmuligheter. Å sitere Brian Lanier "Valgmuligheter er den ene sentinel til å herske dem alle."
Valgmuligheter har to stater, a nil
state, som betyr at valgfri inneholder ingen verdi, og en annen stat, som betyr at den har en gyldig verdi. Tenk på alternativer som en pakke med en indikator for å fortelle om innholdet i pakken er gyldig eller ikke.
Alle typer i Swift kan bli en valgfri. Vi definerer en valgfri ved å legge til en ?
etter typedeklarasjonen slik:
la noenInt: Int? // noenInt == nil
Vi tilordner en verdi til en valgfri pakke, akkurat som vi gjør med konstanter og variabler.
noenInt = 10 // littInt! == 10
Husk at alternativene er som pakker. Da vi erklærte la noenInt: Int?
, Vi definerte en tom boks med en verdi på nil
. Ved å tildele verdien 10
til valgfritt inneholder boksen et heltall som er lik 10
og dens indikator eller tilstand blir ikke null.
For å komme til innholdet i en valgfri bruker vi !
operatør. Vi må være sikre på at tilleggsutstyret har en gyldig verdi før den pakkes ut. Hvis du ikke gjør det, vil det oppstå en kjøretidsfeil. Slik får vi tilgang til verdien som er lagret i en valgfri:
if (someInt! = nil) println ("someInt: \ (someInt!)") else println ("noen har ingen verdi") // noenInt: 10
Ovennevnte mønster er så vanlig i Swift at vi kan forenkle kodeboksen ovenfor ved å bruke valgfri binding med hvis la
søkeord. Ta en titt på den oppdaterte kodeblokken nedenfor.
hvis la verdi = noenInt println ("someInt: \ (verdi)" else println ("noenInt har ingen verdi")
Alternativer er den eneste typen som kan ta en nil
verdi. Konstanter og variabler kan ikke initialiseres eller settes til nil
. Dette er en del av Swifts sikkerhetspolitikk, alle ikke-valgfrie variabler og konstanter må ha en verdi.
Hvis du husker, tilbake da ARC ble introdusert, brukte vi sterk
og svak
søkeord for å definere objekt eierskap. Swift har også a sterk
og svak
eierskapsmodell, men det introduserer også en ny, uten tilsyn
. La oss ta en titt på hver objekt eierskapsmodell i Swift.
sterk
Sterke referanser er standard i Swift. Mesteparten av tiden eier vi objektet som vi refererer til, og vi er de som er ansvarlige for å holde det refererte objektet levende.
Siden sterke referanser er standard, er det ikke nødvendig å eksplisitt holde en sterk referanse til et objekt, noe referanse er en sterk referanse.
svak
En svak referanse i Swift indikerer at referansen peker mot et objekt som vi ikke er ansvarlige for å holde oss i live. Det brukes hovedsakelig mellom to objekter som ikke trenger den andre til å være rundt for at objektet skal fortsette sin livssyklus.
Det er en men, derimot. I Swift må svake referanser alltid være variabler med en valgfri type, fordi de er satt til nil
når det refererte objektet er allokert. De svak
Søkeord brukes til å erklære en variabel som svak:
Svak Var Vis: UIView?
uten tilsyn
Ukjente referanser er nye for Objective-C programmerere. En ukjent referanse betyr at vi ikke er ansvarlige for å holde det refererte objektet levende, akkurat som svake referanser.
Forskjellen med en svak referanse er at en ukjent referanse ikke er satt til nil
når objektet det refererer til, er deallokert. En annen viktig forskjell med svake referanser er at ukjente referanser er definert som en ikke-valgfri type.
Ukjente referanser kan være konstanter. Et ukjent objekt eksisterer ikke uten sin eier og derfor er den ukjente referansen aldri nil
. Ukjente referanser trenger uten tilsyn
søkeord før definisjonen av variabelen eller konstanten.
Ukjent var visning: UIView
Swift er et fantastisk språk som har mye dybde og potensial. Det er morsomt å skrive programmer med, og det fjerner mye av boilerplate-koden vi skriver i Objective-C for å sikre at vår kode er trygg.
Jeg anbefaler The Swift Programming Language, som er tilgjengelig gratis i Apples iBooks Store.