Swift fra Scratch: Access Control and Property Observers

Swift fra Scratch: Access Control og formues Observatører
25
Del
4
Del

Denne Cyber ​​Monday Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av
Dette innlegget er en del av en serie som heter Swift fra Scratch.Swift fra Scratch:. Delegasjon og PropertiesSwift fra Scratch: Initialisering og initializer delegasjon

I forrige tutorial, la vi muligheten til å lage til -Har elementer. Selv om dette tillegg har gjort programmet litt mer nyttig, ville det også være praktisk å legge muligheten til å markere elementer som er gjort og slette elementer. Det er det vi vil fokusere på i denne opplæringen.

Forutsetninger

Hvis du ønsker å følge med meg, så sørg for at du har Xcode 6.3 eller nyere installert på din maskin. I skrivende stund, Xcode 6.3 er i beta og tilgjengelig fra Apples iOS Dev Center til registrerte iOS-utviklere.

Bakgrunnen for å kreve Xcode 6.3 eller høyere er å være i stand til å dra nytte av Swift 1.2, som Apple introdusert i februar. Swift 1.2 introduserer en rekke store filer som vi vil dra nytte av i resten av denne serien.

1. Slette Elementer

For å slette elementer, trenger vi å gjennomføre ytterligere to metoder for UITableViewDataSource protokollen. Vi må først fortelle tabellvisningen som rader kan redigeres ved å implementere den Tableview (_: canEditRowAtIndexPath :) metode. Som du kan se i under kodebiten, er gjennomføringen grei. Vi forteller tabellen oppfatning at hver rad kan redigeres ved å returnere true
func Tableview (Tableview: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath.) - ≫ Bool {return true}

Den andre metoden vi er interessert i er Tableview (_: commitEditingStyle: forRowAtIndexPath :). Gjennomføringen er litt mer komplisert, men lett nok til å forstå
func Tableview. (Tableview: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {if editingStyle == .Delete {//Hente varen la element = selvtillit. varer [indexPath.row] //Oppdater Elementer self.items.removeAtIndex (indexPath.row) //Update Tabell tableView.deleteRowsAtIndexPaths ([indexPath], withRowAnimation: .right)}}

Vi starter med å sjekke verdien av editingStyle, en opplisting av type UITableViewCellEditingStyle. Vi bare slette et element hvis verdien av editingStyle er lik UITableViewCellEditingStyle.Delete.

Swift er smartere enn det selv. Fordi den vet at editingStyle er av typen UITableViewCellEditingStyle, kan vi utelate UITableViewCellEditingStyle, navnet på opptellingen, og skrive .Delete, medlem verdien av opptellingen at vi er interessert i. Hvis du er ny til enumerations i Swift, deretter Jeg anbefaler at du leser denne raske tips om enumerations i Swift.

Neste, vi hente det tilsvarende elementet fra elementer eiendommen og midlertidig lagre sin verdi i en konstant heter element. Vi oppdaterer tabellvisningen datakilde, elementer, ved å påberope removeAtIndex (indeks: Int). På elementer eiendom, passerer i riktig indeks

Til slutt, vi oppdaterer tabellvisningen ved å påberope deleteRowsAtIndexPaths (_: withRowAnimation: ) på Tableview, passerer i en matrise med indexPath og .right å angi animasjon type. Som vi så tidligere, kan vi utelate navnet på telling, UITableViewRowAnimation, siden Swift vet hvilken type det andre argumentet er UITableViewRowAnimation.

Brukeren skal nå være i stand til å slette elementer fra listen. Bygge og kjøre programmet for å teste dette.

2. Kontroll av elementer

Hvis du vil merke et element som fullført, kommer vi til å legge et merke til den tilsvarende raden. Dette innebærer at vi trenger å holde styr på de elementene som brukeren har markert som fullførte. For dette formålet, vil vi erklære en ny eiendom som styrer dette for oss. Deklarere en variabel eiendom, checkedItems, av typen [String] og initialisere den med en tom array
Var checkedItems:. [String] = []

I Tableview (_: cellForRowAtIndexPath :), sjekker vi om checkedItems inneholder respektive element ved hjelp av inneholder funksjonen, en global funksjon definert i Swift Standard Library. Vi passerer i checkedItems som første argument og element som det andre argumentet. Funksjonen returnerer true hvis checkedItems inneholder element
func Tableview (Tableview: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath.) - ≫ UITableViewCell {//Hente varen la element = self.items [indexPath.row] //dequeue Tabell Cell la tableViewCell = tableView.dequeueReusableCellWithIdentifier ("TableViewCell", forIndexPath: indexPath) som! UITableViewCell //Konfigurer Tabell Cell tableViewCell.textLabel? .text = Elementet hvis inneholder (self.checkedItems, element) {tableViewCell.accessoryType = .Checkmark} else {tableViewCell.accessoryType = .None} returnere tableViewCell}

Hvis elementet er funnet i checkedItems, setter vi cellens accessoryType eiendom til .Checkmark, medlem verdien av UITableViewCellAccessoryType telling. Hvis varen ikke blir funnet, vi faller tilbake til .None som cellens tilbehørstype.

Det neste trinnet er å legge til muligheten til å merke et element som gjøres ved å implementere en metode for UITableViewDelegate protokollen, Tableview ( _: didSelectRowAtIndexPath :). I denne delegat metoden, må vi først ringe deselectRowAtIndexPath (_: animert :) på Tableview for å oppheve rad brukeren tappet
//MARK:. Tabell Deleger Methodsfunc Tableview (Tableview: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {Tableview. deselectRowAtIndexPath (indexPath, animert: true) //Fetch Element la element = self.items [indexPath.row] //Fetch Tabell Cell la tableViewCell = tableView.cellForRowAtIndexPath (indexPath) //Finn Index of Element la index = finne (selv .checkedItems, punkt) hvis la index = index {self.checkedItems.removeAtIndex (index) tableViewCell? .accessoryType = UITableViewCellAccessoryType.None} else {self.checkedItems.append (post) tableViewCell? .accessoryType = UITableViewCellAccessoryType.Checkmark}}

Vi deretter hente tilsvarende elementet fra elementer og en referanse til cellen som korresponderer med den tappet rad. Vi bruker søkefunksjonen, definert i Swift Standard Bibliotek, for å få indeksen element i checkedItems. Funnet funksjonen returnerer en valgfri Int. Hvis checkedItems inneholder element, fjerner vi det fra checkedItems og sette cellens tilbehørstype til .None. Hvis checkedItems ikke inneholder element, vi legger det til checkedItems og sette cellens tilbehørstype til .Checkmark.

Med disse tilleggene, er brukeren nå i stand til å merke elementer som gjøres. Bygge og kjøre programmet for å være sikker på at alt fungerer som forventet.

3. Besparende State

Programmet for tiden ikke lagre tilstand mellom lanseringer. For å løse dette, kommer vi til å lagre elementer og checkedItems arrays i brukerstandarder database for programmet.

Trinn 1: Legge State

Start med å lage to hjelpemetoder loadItems og loadCheckedItems. Legg merke til den private søkeord prefixing hver helper metode. Den private søkeord forteller Swift at disse metodene er bare tilgjengelig fra denne kilden filen
//MARK:. Private Helpersprivate funk loadItems () {la userDefaults = NSUserDefaults.standardUserDefaults () hvis la elementer = userDefaults.objectForKey ("elementer" ) som? [String] {self.items = varer}} private funk loadCheckedItems () {la userDefaults = NSUserDefaults.standardUserDefaults () hvis la checkedItems = userDefaults.objectForKey ("checkedItems") som? [String] {self.checkedItems = checkedItems}}

Den private søkeord er en del av Swifts adgangskontroll. Som navnet tilsier, definerer tilgangskontroll hvilken kode har tilgang til hvilken kode. Tilgangsnivåer gjelder metoder, funksjoner, typer, etc. Apple refererer bare til enheter. Det er tre tilgangsnivåer, offentlige, interne og private

Offentlige:. Entities markert som offentlig er tilgjengelig med enheter som er definert i samme modul samt andre moduler. Dette tilgangsnivået er ideell for å utsette grensesnittet til et rammeverk

Intern:. Dette er standard tilgangsnivå. Med andre ord, dersom ingen tilgangsnivå er spesifisert, gjelder dette tilgangsnivå. Et foretak med tilgangsnivået internt er bare tilgjengelig med enheter som er definert i samme modul

Privat. Et foretak deklarert som private er bare tilgjengelig med enheter som er definert i samme kildefilen. For eksempel, de private hjelpemetoder definert i ViewController klassen er bare tilgjengelig med ViewController klassen.

Gjennomføring av hjelpemetoder er enkelt hvis du er kjent med NSUserDefaults klassen. For brukervennlighet, lagrer vi en referanse til standard bruker mislighold objekt i en konstant kalt userDefaults. I tilfelle av loadItems, ber vi userDefaults for objektet forbundet med nøkkel "elementer" og nedbrutte det til en valgfri rekke strenger. Vi trygt pakke den valgfrie, noe som betyr at vi lagrer verdien i de konstante elementer hvis den valgfrie er ikke null, og tildele verdi til elementer eiendommen.

Dersom hvis setningen ser forvirrende, så ta en titt på en enklere versjon av loadItems metoden i det følgende eksempel. Resultatet er identiske, den eneste forskjellen er knapphet.
Private funk loadItems () {la userDefaults = NSUserDefaults.standardUserDefaults () la storedItems = userDefaults.objectForKey ("items") som? [String] hvis la varer = storedItems {self.items = elementer}}

Gjennomføringen av loadCheckedItems er identiske med unntak av nøkkelen brukes til å laste objektet lagret i brukerstandarder database. La oss sette loadItems og loadCheckedItems å bruke ved å oppdatere viewDidLoad metoden.
Styre func viewDidLoad () {super.viewDidLoad () //Set Tittel self.title = "To Do" //belastningstilstanden self.loadItems () selv. loadCheckedItems () //Register klasse for Cell Gjenbruk self.tableView.registerClass (UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")}
Trinn 2: Saving State

For å spare staten, implementerer vi to mer privat hjelpemetoder, saveItems og saveCheckedItems. Logikken er lik som loadItems og loadCheckedItems. Forskjellen er at vi lagrer data i brukerstandarder database. Sørg for at tastene brukes i setObject (_: Forkey :) samtaler matche de brukes i loadItems og loadCheckedItems
private funk saveItems () {lar userDefaults = NSUserDefaults.standardUserDefaults () //Oppdater Bruker Defaults userDefaults.setObject (. self.items, Forkey: "varer") userDefaults.synchronize ()} private funk saveCheckedItems () {la userDefaults = NSUserDefaults.standardUserDefaults () //Oppdater Bruker Defaults userDefaults.setObject (self.checkedItems, Forkey: "checkedItems") userDefaults .synchronize ()}

Synkroniser samtalen ikke er strengt nødvendig. Operativsystemet vil sørge for at dataene du lagre i brukerstandarder database skrives til disk på et tidspunkt
. Ved å påberope synkronisere, men du eksplisitt ber operativsystemet å skrive ventende endringer disk. Dette er nyttig under utvikling, fordi operativsystemet ikke vil skrive endringene til disk hvis du dreper programmet. Det kan da virke som om noe ikke fungerer som den skal.

Vi trenger å påberope saveItems og saveCheckedItems i en rekke steder. Hvis du vil starte, ring saveItems når en ny artikkel er lagt til listen. Vi gjør dette i representantens metoden i AddItemViewControllerDelegate protokollen
//MARK:. Legg til element View Controller Deleger Methodsfunc kontrolleren (controller: AddItemViewController, didAddItem: String) {//Oppdater datakilde self.items.append (didAddItem) //Save State self.saveItems () //Last Tabell self.tableView.reloadData () //Avvis Legg til element View Controller self.dismissViewControllerAnimated (sant, ferdigstillelse: null)}

Når staten til et element endringer i Tableview (_: didSelectRowAtIndexPath :), oppdaterer vi checkedItems. Det er en god idé å også påberope saveCheckedItems på det punktet
//MARK:. Tabell Deleger Methodsfunc Tableview (Tableview: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {tableView.deselectRowAtIndexPath (indexPath, animert: true) //Fetch Element la element = self.items [indexPath.row] //Fetch Tabell Cell la tableViewCell = tableView.cellForRowAtIndexPath (indexPath) //Finn Index of Element la index = finne (self.checkedItems, element) hvis la index = index {selv. checkedItems.removeAtIndex (indeks) tableViewCell? .accessoryType = UITableViewCellAccessoryType.None} else {self.checkedItems.append (post) tableViewCell? .accessoryType = UITableViewCellAccessoryType.Checkmark} //Save State self.saveCheckedItems ()}

Når et element slettes, blir begge elementene og checkedItems oppdatert. For å lagre denne endringen, kaller vi både saveItems og saveCheckedItems
func Tableview. (Tableview: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {if editingStyle == .Delete {//Hente varen la element = self.items [indexPath.row] //Oppdater Elementer self.items.removeAtIndex (indexPath.row) hvis inneholder (self.checkedItems, element) {self.checkedItems.removeAtIndex (indexPath.row)} //Save State self.saveItems () selv .saveCheckedItems () //Update Tabell tableView.deleteRowsAtIndexPaths ([indexPath], withRowAnimation: UITableViewRowAnimation.Right)}}

Det var det. Bygge og kjøre programmet for å teste arbeidet ditt. Spill med søknaden og kraft avslutte den. Når du starter programmet på nytt, bør den siste kjente staten lastes og synlig.

4. Eiendoms Observatører

programmets brukeropplevelsen er litt mangelfull i øyeblikket. Når hvert element slettes eller når programmet startes for første gang, ser brukeren en tom tabellvisning. Dette er ikke bra. Vi kan løse dette ved å vise en melding når det er ingen elementer. Dette vil også gi meg muligheten til å vise deg en annen funksjon i Swift, eiendom observatører

Trinn 1:. Legge til en etikett

La oss begynne med å legge en etikett til brukergrensesnittet for å vise meldingen . Erklære en stikkontakt som heter messageLabel av type UILabel i ViewController klasse, åpen Main.storyboard, og legge til en etikett til visningen kontrolleren syn
IBOutlet Var messageLabel:.! UILabel

Legg de nødvendige layout begrensninger til etiketten og koble den med utsikt kontrollerens messageLabel uttaket i Connections Inspector. Sett etikettens teksten du ikke har noen gjøremål. og sentrer etiketten tekst i Attributter Inspector

Trinn 2:. Implementering av en eiendom Observer

Meldingen etiketten skal bare være synlig hvis elementer inneholder ingen elementer. Når det skjer, bør vi også skjule tabellvisningen. Vi kunne løse dette problemet ved å legge til ulike kontroller i ViewController klassen, men en mer praktisk og elegant tilnærming er å bruke en eiendom observatør.

Som navnet tilsier, eiendoms observatører observere en eiendom. En egenskap observatør blir startet når en egenskap det samme, selv når den nye verdien er den samme som den gamle verdi. Det finnes to typer av observatører

willSet. Påberopes før verdien har endret

didSet: påberopes etter at verdien er endret

For vår formål, vil vi gjennomføre didSet observatør for elementer eiendommen. Ta en titt på syntaksen i følgende kodebiten
Var poster:. [String] = [] {didSet {la hasItems = items.count > 0 self.tableView.hidden =! HasItems self.messageLabel.hidden = hasItems}}

Konstruksjonen kan se litt rart i begynnelsen, så la meg forklare hva som skjer. Når didSet observatør startes, etter at eks eiendommen har endret seg, sjekker vi om elementer Eiendommen inneholder noen elementer. Basert på verdien av de hasItems konstant, vi oppdaterer brukergrensesnittet. Det er så enkelt som det.

didSet observatør er gått en konstant parameter som inneholder verdien av den gamle verdien av eiendommen. Det er utelatt i eksempelet ovenfor, fordi vi ikke trenger det i vår gjennomføring. Følgende eksempel viser hvordan det kunne brukes
Var elementer:.! [String] = [] {didSet (oldValue) {if oldValue = elementer {la hasItems = items.count > 0 self.tableView.hidden =! HasItems self.messageLabel.hidden = hasItems}}}

oldValue parameter i eksempelet ikke har en eksplisitt typen, fordi Swift vet hvilken type elementer eiendom. I eksempelet, vi bare oppdaterer brukergrensesnittet hvis den gamle verdien avviker fra den nye verdien.

En willSet observatør fungerer på en lignende måte. Den viktigste forskjellen er at para sendes til willSet observatør er en konstant holder den nye verdien av eiendommen. Når du bruker eiendoms observatører, husk at de ikke er påberopt når forekomsten er initialisert.

Bygg og kjøre programmet for å kontrollere at alt er koblet riktig. Selv om programmet ikke er perfekt og kunne bruke noen flere funksjoner, du har opprettet din første iOS program som bruker Swift.

Konklusjon

I løpet av de siste tre leksjonene i denne serien opprettet du en funksjonell iOS program som bruker Swifts objektorienterte egenskaper. Hvis du har litt erfaring programmering og utvikling av applikasjoner, så du må ha lagt merke til at dagens datamodellen har noen mangler, for å si det forsiktig. Lagring av elementer som strenger og skape et eget utvalg for å lagre et element tilstand er ikke en god ide hvis du bygger et skikkelig program. En bedre tilnærming ville være å opprette en egen ToDo klasse for modellering elementer og lagre dem i programmets sandkasse. Det vil være vårt mål for den neste utgaven av denne serien.