En introduksjon til Swift: Part 2

An Introduksjon til Swift: Part 2
73
Del
6
Del
Dette Cyber ​​mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.

I den første artikkelen i denne innledende serien på Swift, snakket vi om Swift filosofi, tok en første titt på dens syntaks, og fremhevet noen viktige forskjeller med Objective-C. I denne artikkelen, vi fortsetter vår utforskning av Swifts syntaks. Du vil også lære om optionals og se hvordan minnehåndtering fungerer i Swift.

1. Conditionals og Loops

Hvis

Hvis uttalelsene er identisk i Swift og Objective-C med unntak av to små forskjeller:

parentes rundt tilstanden variabel er valgfritt

klammeparentes er pålagt

Dette er omtrent de eneste forskjellene med hvis uttalelser i Objective-C.

Ranges

Som vi så i den første artikkelen, Swift inkluderer to utvalg operatører .. < og ... for å angi en rekke verdier. Disse to operatører er halv lukket utvalg operatør Hotell og lukket utvalg operatør

En halv lukket område, for eksempel en .. <.; 5, representerer verdiene 1, 2, 3 og 4, med unntak av 5. En lukket område, så som 1 ... 5, representerer verdiene 1, 2, 3, 4, og innbefatter 5.

Ranges kan brukes i for looper, matrise senket, og selv i bryter uttalelser. Ta en titt på følgende eksempler
//for loop examplefor jeg i en ... ≪ 10 {} //gjentas fra 1 til 9 //rekke senket examplelet someArray = ["eple", "pair "," fersken "," vannmelon "," jordbær "] for frukt i someArray [2 .. < 4] {println (frukt)} //utganger: fersken og vannmelon //slå exampleswitch someInt {case 0: //gjøre noe med 0 tilfelle en .. < 5: //gjøre noe med 1,2,3,4 tilfelle 5 ... 10: //gjøre noe med 5,6,7,8,9,10 standard: //alt annet}
Slå

Bytt uttalelser er kraftigere i Swift enn de er i Objective-C. I Objective-C, må et resultat av ekspresjonen av en bryter uttalelse å være av typen heltall og verdiene for hvert enkelt tilfelle utsagn skal være en konstant eller en konstant uttrykk. Dette er ikke sant i Swift. I Swift, kan saken uttalelser være av alle typer, inkludert områder.

I Swift, har bryteren ingen pause uttalelser og det ikke automatisk falle gjennom fra en sak til en annen. Når du skriver en bryter uttalelse, må man sørge for at alle forhold blir håndtert av sine case uttalelser, unnlater å gjøre dette vil resultere i en kompilator feil. En sikker måte å dekke alle forhold er å inkludere en standard sak uttalelse

Her er et eksempel på en bryter uttalelse med String tilfeller.
La vegetabilsk = "red pepper" bryteren vegetabilsk {case " selleri ": la vegetableComment =" Legg til litt rosiner og gjøre maur på en log "case" agurk "," brønnkarse. ": la vegetableComment =" Det ville gjøre en god te sandwich. "default: la vegetableComment =" Alt smaker godt i suppe. "}

I Swift, case uttalelser ikke faller gjennom som standard. Dette var et bevisst valg for å unngå vanlige feil. Hvis en konkret sak må falle gjennom, kan du bruke fallthrough nøkkelord for å indikere dette til kompilatoren
slå someInt {case 0:. //Gjøre noe med 0 case 1: //gjør noe med en sak 2: //gjøre noe med to fallthrough standard: //gjøre noe for alt annet} //tilfelle 2 vil falle gjennom å misligholde saken

Det stopper ikke her. Swift legger til to andre funksjoner for å bytte, verdi bindinger Hotell og der
klausul
. Verdi bindende brukes med saken la søkeord for å binde en konstant med matchende saken. Den der klausulen gir en ekstra betingelse for saken uttalelsen bruker der søkeordet.

Disse to konseptene er bedre forklart med eksempler. Følgende kode blokken viser hvordan verdi bindende
fungerer
la somepoint =. (X-aksen: 2, yAkse: 0) bryter somepoint {saken (la x, 0): println ("på x-aksen med en x-verdi på \\ (x) ") case (0, la y): println (" på y-aksen med en y-verdi av \\ (y) ") fall la (x, y): println (" et annet på (\\ (x), \\ (y)) ")}

Det første tilfellet uttalelse, sak (la x, 0), vil samsvare med verdiene der yAkse er lik 0 og noen verdi for x-aksen, og vi binder xAkse til konstant x som skal brukes inne i saken uttalelsen

Her er et eksempel på hvor klausul i aksjon
la vegetabilsk = "red pepper" bryteren vegetabilsk {case "selleri".. println (" Legg noen rosiner og gjøre maur på en log ") fall la x hvor x.hasSuffix. (" pepper "): println (" Jeg er allergisk mot \\ (x) ") standard: println (" Alt smaker godt i suppe. ")} //utganger: Jeg er allergisk mot rød pepper
2. Funksjoner og nedleggelser

funksjoner

Definere funksjoner og nedleggelser er lett i Swift. Objective-C utviklere kjenner dem bedre som funksjoner og blokker.

I Swift, kan funksjonsparametere har standardverdier, som minner om skriptspråk som PHP og Ruby.

Syntaksen for funksjonene er som følger:
func function (parameterName: Type = Default) - > returnType {[...] retur returnType;}

For å skrive et sayHello funksjon som tar et parameternavn av type String og returnerer en Bool når vellykket, skriver vi følgende:
func sayHello (navn: String) - > Bool {println ("hallo \\ (navn)"); return true;} sayHello ("World") //utgang //Hello World

For å bestå en standardverdi for navnet parameter, funksjonens implementering vil se ut som følger:
func sayHello (navn: String = "World ") - > Bool {println ("hallo \\ (navn)"); return true;} sayHello () //utgang //hei WorldsayHello ("mike") //utgang //hei mike

En funksjon som er helt fraværende i Objective-C er tuples
. I Swift kan funksjoner returnere flere verdier i form av en tuppel. Tupler blir behandlet som en enkelt variabel, noe som betyr at du kan sende den rundt akkurat som en variabel.

tupler er svært enkel å bruke. Faktisk har vi allerede jobbet med tupler i den forrige artikkelen når vi nummerert en ordbok. I neste kodebiten, er nøkkel /verdi-paret en tuppel.
For (nøkkel, verdi) i someDictionary {println ("Key \\ (key) har verdi \\ (verdi)"}

Hvordan blir tupler brukt og hvordan kan du dra nytte av dem? La oss ta en titt på et annet eksempel. La oss endre ovenfor sayHello funksjonen til å returnere en boolsk når vellykket samt den resulterende meldingen. Vi gjør dette ved å returnere et tuppel, (Bool, String). Den oppdatert sayHello funksjonen ser slik ut:
func sayHello (navn: String = "World") - > (Bool, String) {la hilsen = "hallo \\ (navn)" return (sant, gratulasjon);} la ( suksess, hilsen) = sayHello () println ("sayHello returnert suksess: \\ (suksess) med hilsen: \\ (hilsen)"); //utgang //sayHello returnert suksess: en med hilsen: Hei Verden

tupler har vært på ønskelisten til mange Objective-C programmerere for en lang tid.

En annen kul funksjon av tupler er at vi kan kalle de returnerte variabler. Hvis vi tilbake til forrige eksempel og gi navn til variablene i tuppel , får vi følgende:
func sayHello (navn: String = "World") - > (suksess: Bool, hilsen: String) {la hilsen = "hallo \\ (navn)" return (sant, gratulasjon);} la status = sayHello () println ("sayHello returnert suksess: \\ (status.success) med hilsen: \\ (status.greeting) "); //utgang //sayHello returnert suksess: en med hilsen: Hei Verden

Dette betyr at i stedet for å definere en egen konstant for hver retur element i et tuppel, kan vi få tilgang til den returnerte tuppel elementer ved hjelp av dot notasjon som vist i eksempelet ovenfor, status.success og status.greeting.

Nedleggelser

Nedlegging i Swift er de samme som blokker i Objective-C. De kan defineres inline, sendes som en parameter, eller returneres av funksjoner. Vi bruker dem akkurat som vi ville bruke blokker i Objective-C.

Definere nedleggelser er også enkelt. Egentlig er en funksjon et spesialtilfelle av nedleggelser. Så det er ikke rart at definere en nedleggelse ser mye som definerer en funksjon.

Nedleggelser er et førsteklasses typen, noe som betyr at de kan sendes og returnert av funksjoner akkurat som en hvilken som helst annen type, for eksempel Int , String, bool, osv Nedleggelser er i hovedsak kodeblokker som kan kalles senere og har tilgang til omfanget der de ble definert.

Opprette en navnløs nedleggelse er så enkelt som å pakke en blokk med kode i krøllete bukseseler. Parametre og returnere type nedleggelsen er atskilt fra nedleggelse kropp med i søkeord

La oss si at vi ønsker å definere en nedleggelse som returnerer true hvis et tall er enda, så det nedleggelse kunne se omtrent slik ut.:
la isEven = {(antall: Int) - > Bool fjord mod = antall% 2return (mod == 0)}

isEven nedleggelse tar en Int som sin eneste parameter og returnerer en bool. Typen denne nedleggelsen er (antall: Int) - > Bool, eller (Int - > bool) for kort. Vi kan kalle isEven hvor som helst i koden vår akkurat som vi ville kalle en kodeblokk i Objective-C.

Å passere en nedleggelse av denne typen som en parameter til en funksjon, bruker vi nedleggelsen type i funksjonen definisjon :
la isEven = {(antall: Int) - > Bool i la mod = antall% 2; avkastning (mod == 0);} func verifyIfEven (antall: Int, kontrolløren: (Int- > Bool)) - > Bool {return kontrolløren (antall);} verifyIfEven (12, isEven); //returnerer trueverifyIfEven ( 19, isEven); //returnerer false

I eksempelet ovenfor, er den som skal verifisere parameter i verifyIfEven funksjon en nedleggelse som vi sender til funksjonen

3.. Klasser & Konstruksjoner

Klasser

Det er på tide å snakke om selve grunnlaget for objektorientert programmering, klasser. Klasser, som nevnt før, er definert i en enkelt fil gjennomføring med en .swift
forlengelse. Eiendoms erklæringer og metoder er alle definert i denne filen.

Vi skaper en klasse med klassen nøkkelordet etterfulgt av navnet på klassen. Klassen implementering er pakket inn i et par av klammeparentes. Som i Objective-C, er navnekonvensjonen for klasser å bruke øvre kamel sak for klasse navn
class Hotel {//egenskaper //funksjoner}

For å opprette en forekomst av Hotellklasse vi skriver.
la h = Hotel ()

I Swift, er det ingen grunn til å kalle init på objekter som init kalles automatisk for oss.

Klasse arv følger samme mønster som i Objective-C, et kolon skiller klassenavnet og at den er super. I følgende eksempel, arver Hotel fra BigHotel klassen
klasse BigHotel. Hotel {}

Som i Objective-C, bruker vi dot notasjon for å få tilgang til et objekt. Men bruker Swift også dot notasjon til å påberope klasse- og instansmetoder som du kan se nedenfor
//Objective-CUIView * view = [[UIView Alloc] init] [self.view addSubview: view];. //swiftlet view = UIView () self.view.addSubview (vis)
Egenskaper

En annen forskjell med Objective-C er at Swift ikke skiller mellom instansvariabler (Ivars) og egenskaper. Et eksempel variabelen er en eiendom.

Erklærte en eiendom er akkurat som å definere en variabel eller konstant, bruker var og la søkeord. Den eneste forskjellen er i hvilken sammenheng de er definert, det vil si rammen av en klasse
class Hotel {la rom = 10 Var fullRooms = 0}.

I eksempelet ovenfor, er rommene en uforanderlig verdi, en konstant, satt til 10 og fullRooms er en variabel med en initial verdi på 0, som vi kan endre senere. Regelen er at eiendommene må være initialisert når de er erklært. Det eneste unntaket fra denne regelen er optionals, som vi vil diskutere i et øyeblikk.

Computed Properties

Swift språket definerer også beregnede egenskaper. Beregnede egenskaper er noe mer enn fancy kundeskaffere og settere som ikke lagrer en verdi. Som navnet tilsier, er de beregnet eller vurdert på fly.

Nedenfor er et eksempel på en beregnet eiendom. Jeg har endret rom eiendom til en VAR for resten av disse eksemplene. Du vil finne ut hvorfor senere
klasse Hotel {var rom = 10 Var fullRooms = 0 Var beskrivelse:. String {får {return "Size of Hotel: \\ (rom) rom kapasitet: \\ (fullRooms) /\\ (rom ) "}}}

Fordi beskrivelsen eiendommen er skrivebeskyttet og bare har en retur uttalelse, kan vi utelate get søkeord og klammeparentes, og bare holde tilbake uttalelsen. Dette er stenografi og det er det jeg skal bruke i resten av denne opplæringen
klassen Hotel {var rom = 10 Var fullRooms = 0 Var beskrivelse:. String {return "Size of Hotel: \\ (rom) rom kapasitet: \\ (fullRooms) /\\ (rom) "}}

Vi kan også definere lese-skrive beregnede egenskaper. I vår klasse Hotel, ønsker vi en emptyRooms eiendom som blir antallet tomme rom på hotellet, men vi ønsker også å oppdatere fullRooms når vi setter de emptyRooms beregnede eiendom. Vi kan gjøre dette ved hjelp av settet søkeord som vist nedenfor
class Hotel {var rom = 10 Var fullRooms = 0 Var beskrivelse:. String {return "Size of Hotel: \\ (rom) rom kapasitet: \\ (fullRooms) /\\ (rom) "} Var emptyRooms: Int {få {return rom - fullRooms} sett {//nyVerdi konstant er tilgjengelig her //inneholder passert verdien if (NewValue < rom) {fullRooms = rom - NewValue} else {fullRooms = rom}}}} la h = Hotel () h.emptyRooms = 3h.description //Størrelse Hotel: 10 rom kapasitet: 7/10

I emptyRooms setter, den nyVerdi konstant er overlevert til oss og representerer verdi sendes til fuglehunden. Det er også viktig å merke seg at beregnede egenskaper er alltid deklarert som variabler, etter VaR søkeord, fordi deres beregnede verdien kan endres.

Metoder

Vi har allerede dekket funksjoner tidligere i denne artikkelen. Metoder er noe mer enn funksjoner som er knyttet til en type, for eksempel en klasse. I det følgende eksemplet vi gjennomføre en instansmetode, bookNumberOfRooms, i Hotellklasse vi opprettet tidligere
class Hotel {var rom = 10 Var fullRooms = 0 Var beskrivelse:. String {return "Size of Hotel: \\ (rom) rom Kapasitet: \\ (fullRooms) /\\ (rom) "} Var emptyRooms: Int {få {return rom - fullRooms} sett {//nyVerdi konstant er tilgjengelig her //inneholder passert verdien if (nyVerdi < rom) {fullRooms = rom - NewValue} else {fullRooms = rom}}} funk bookNumberOfRooms (rom: Int = 1) - > Bool {if (self.emptyRooms > rom) {self.fullRooms ++; return true} else {return false}}} la h = Hotel () h.emptyRooms = 7h.description //Størrelse Hotel: 10 rom kapasitet: 3 /10h.bookNumberOfRooms (rom: 2) //returnerer trueh.description //Størrelse på Hotel: 10 rom kapasitet: 5 /10h.bookNumberOfRoom () //returnerer trueh.description //Størrelse Hotel: 10 rom kapasitet: 6/10
Initializers

Standard initializer for klasser er init. I init-funksjonen, setter vi de første verdiene av forekomsten som er opprettet.

For eksempel, hvis vi trenger en Hotel underklasse med 100 rom, så vi trenger en initializer å stille rom eiendommen til 100 . Husk at jeg tidligere har endret rom fra å være en konstant til å være en variabel i Hotel klassen. Årsaken er at vi ikke kan endre arvet konstanter i en underklasse, kan bare arvet variabler endres
klasse BigHotel. Hotell {init () {super.init () rom = 100}} la bh = BigHotel () println ( bh.description); //Størrelse på Hotel: 100 rom kapasitet: 0/100

Initializers kan også ta parametere. Følgende eksempel viser hvordan dette fungerer
klassen CustomHotel. Hotel {init (størrelse: Int) {super.init () rom = størrelse}} la c = CustomHotel (størrelse: 20) c.description //Størrelse Hotell: 20 rom kapasitet: 0/20
Overordnede Metoder og Computed Properties

Dette er en av de kuleste tingene i Swift. I Swift, kan en underklasse styre begge metodene og beregnede egenskaper. For å gjøre dette, bruker vi overstyring søkeord. La oss overstyre beskrivelsen beregnet eiendom i CustomHotel Klasse:
klasse CustomHotel: Hotel {init (størrelse: Int) {super.init () rom = størrelse} overstyring Var beskrivelse: String {return super.description + "Howdy!" }} la c = CustomHotel (størrelse: 20) c.description //Størrelse på Hotel: 20 rom kapasitet: 0/20 Howdy

Resultatet er at beskrivelse returnerer resultatet av superklassen sin beskrivelse metoden med strengen "Howdy ! " føyd til det.

Hva er kult om overordnede metoder og beregnede eiendommer er overstyrings nøkkelordet. Når kompilatoren ser overstyring søkeord, sjekker den vær klassens super implementerer metoden som blir overstyrt. Kompilatoren sjekker også om egenskapene og metodene i en klasse er i konflikt med egenskaper eller metoder høyere opp arven treet.

Jeg vet ikke hvor mange ganger en skrivefeil i en overstyrt metode i Objective-C laget meg forbanne, fordi koden ikke virket. I Swift, vil kompilatoren fortelle deg nøyaktig hva som er galt i disse situasjonene.

Structures

Structures, definert med struct søkeord, er kraftigere i Swift enn de er i C og Objective-C . I C, structs definere bare verdier og pekere. Swift structs er akkurat som C structs, 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:.
< li> trenger strukturer ikke støtter arv som klassene

strukturer er gått rundt i verdi mens klassene er vedtatt av referansen

Her er noen eksempler på strukturer i Swift:
struct Rektangel {var opprinnelsen: Point Var størrelse: Størrelse Var område: Double {return size.width * size.height} func isBiggerThanRect (r: Rect) - > Bool {return (self.area > r.area)}} struct Point {var x = 0 Var y = 0} struct Størrelse {var width = 0 Var height = 0}
4. Optionals

løsning på et problem

optionals er et nytt konsept hvis du kommer fra Objective-C. De løse et problem vi alle står overfor som programmerere. Når vi tilgang til en variabel som har en verdi vi er ikke sikker på om vi som regel tilbake en indikator, kjent som et fast punkt, for å indikere at den returnerte verdien er en no-verdi. La meg illustrere dette med et eksempel fra Objective-C:
NSString * someString = @ "ABCDEF"; NSInteger pos = [someString rangeOfString: @ "B"]. Location; //pos = 1

I de ovennevnte eksempel, prøver vi å finne posisjonen @ "B" i someString. Hvis @ "B" er funnet, er dens plassering eller posisjon lagres i pos. Men hva skjer hvis @ "B" er ikke funnet i someString

Dokumentasjonen sier at rangeOfString:? Returnerer en NSRange med beliggenhet satt til NSNotFound konstant. I tilfelle av rangeOfString :, sentinel er NSNotFound. Sentinels er brukt for å indikere at den returnerte verdien er ugyldig.

I Cocoa, det er mange bruksområder for dette konseptet, men sentinel verdien avviker fra kontekst til kontekst, 0, -1, NULL, NSIntegerMax, INT_MAX , Nil, etc. Problemet for programmereren er at hun må huske hvilken sentinel brukes i hvilken sammenheng. Hvis programmereren ikke er forsiktig, kan hun feil en gyldig verdi for en sentinel og vice versa. Swift løser dette problemet med optionals. For å sitere Brian Lanier "Tilleggsutstyr er den ene sentinel å styre dem alle."

Tilleggsutstyr ha to stater, en null, betyr det valgfrie inneholder ingen verdi, og en annen stat, noe som betyr at det har gyldig verdi. Tenk på optionals som en pakke med en indikator for å fortelle deg om pakkenes innhold er gyldig eller ikke.

Bruks

Alle typer i Swift kan bli et valgfritt. Vi definerer et valgfritt ved tilsetning av en? etter type erklæring som så:
la someInt:?. Int //someInt == null

Vi tildeler en verdi til en valgfri pakke akkurat som vi gjør med konstanter og variabler
someInt = 10 //someInt ! == 10

Husk at optionals er som pakker. Når vi erklærte la someInt: Int ?, vi definert en tom boks med en verdi på null. Ved å tilordne verdien 10 til valgfritt, inneholder boksen et heltall som er lik 10 og dens indikator eller tilstand blir ikke nil
.

For å komme til innholdet i en valgfri vi bruker de ! operatør. Vi må være sikker på at den valg har en gyldig verdi før pakker det. Unnlate å gjøre dette vil føre til en runtime error. Dette er hvordan vi tilgang til verdien som er lagret i en valgfri:
if (! SomeInt = null) {println ("someInt: \\ (someInt)")} else {println ("someInt har ingen verdi")} //someInt: 10

Listen mønsteret er så vanlig i Swift at vi kan forenkle koden ovenfor blokken ved hjelp av valgfri binding
med hvis lar søkeord. Ta en titt på den oppdaterte kodeblokken under
hvis la verdi = someInt {println ("someInt: \\ (verdi)")}. Else {println ("someInt har ingen verdi")}

Tilleggsutstyr er den eneste type som kan ta en null verdi. Konstanter og variabler kan ikke initialiseres eller satt til null. Dette er en del av Swift sikkerhetspolitikk, alle ikke-valg variabler og konstanter
ha en verdi.

5. Minnehåndtering

Hvis du husker, tilbake når ARC ble introdusert vi brukte de sterke og svake søkeord for å definere objekt eierskap. Swift har også en sterk og svak eierskapsmodell, men det introduserer også en ny en uten tilsyn. La oss ta en titt på hvert objekt eierskapsmodell i Swift.

sterk

Sterke referanser er standard i Swift. Mesteparten av tiden, eier vi objektet som vi henviser, og vi er de som er ansvarlig for å holde den refererte objektet i live.

Siden sterke referanser er standard, er det ikke nødvendig å eksplisitt holde en sterk referanse til et objekt, er enhver referanse en sterk referanse.

svak

En svak referanse i Swift indikerer at referansepunkter til et objekt som vi ikke er ansvarlige for å holde i live. Det er hovedsakelig brukt mellom to objekter som ikke trenger den andre til å være rundt for at objektet for å fortsette sin livssyklus.

Det er en men
, imidlertid. I Swift, må svake referanser alltid være variabler med en valgfri type, fordi de er satt til null når den refererte objektet deallocated. Den svake nøkkelordet brukes til å erklære en variabel som svak:
svak Var Vis:? UIView
uten tilsyn

uten tilsyn referanser er ny for Objective-C programmerere. En uten tilsyn referanse betyr at vi ikke er ansvarlig for å holde den refererte objektet i live, akkurat som svake referanser.

Forskjellen med en svak referanse er at en uten tilsyn referansen ikke er satt til null når objektet den refererer til er deallocated. En annen viktig forskjell med svake referanser er at uten tilsyn referanser er definert som en ikke-valgfri type.

uten tilsyn referanser kan være konstanter. En uten tilsyn objekt ikke eksisterer uten sin eier og derfor uten tilsyn referansen er aldri null. Uten tilsyn referanser trenger uten tilsyn søkeord før definisjonen av variabel eller konstant Anmeldelser uten tilsyn Var Vis:. UIView
Konklusjon

Swift er et fantastisk språk som har mye dybde og potensial. Det er gøy å skrive programmer med og det fjerner mye av standardtekst koden vi skrive i Objective-C for å sørge for at koden vår er trygg.

Jeg anbefaler The Swift Programming Language, som er gratis tilgjengelig i Apples iBooks Store.