Core Data- og Swift: subclassing NSManagedObject
17
Del
3
Del
Dette Cyber mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av
Dette innlegget er en del av en serie kalt kjernedata og Swift.Core Data- og Swift. MigrationsCore Data- og Swift: Samtidighet
1. Innledning
Tidligere i denne serien, skapte vi gjort, et enkelt program for å lære mer om NSFetchedResultsController klassen. I dette prosjektet har vi brukt nøkkelverdien koding (KVC) og nøkkelverdi observere (KVO) å opprette og oppdatere poster. Dette fungerer fint, men fra det øyeblikket prosjektet har noen form for kompleksitet, vil du raskt får problemer. Ikke bare er KVC syntaks ordrik, valueForKey (_ :) og SetValue (_: Forkey :), kan det også introdusere feil som er et resultat av skrivefeil. Følgende kodebit illustrerer dette problemet godt
record.setValue (NSDate (), Forkey: "createdat"). Record.setValue (NSDate (), Forkey: "CreatedAt") record.setValue (NSDate (), Forkey: "createdAt") record.setValue (NSDate (), Forkey: "CREATEDAT")
Hver uttalelse i ovennevnte kodebiten returnerer et annet resultat. Faktisk vil enhver uttalelse resultere i et unntak bortsett fra tredje setningen, som bruker riktig nøkkel som angitt i datamodellen.
Ovennevnte problem er lett løses ved å bruke string konstanter, men det er ikke poenget Jeg prøver å gjøre. Nøkkelverdi koding er flott, men det er ordrik og vanskelig å lese hvis du er vant til Swifts dot syntaks. For å gjøre arbeidet med NSManagedObject tilfeller lettere, er det bedre å lage en NSManagedObject underklasse for hver enhet av datamodellen og det er hva du vil lære i denne artikkelen.
2. Subclassing NSManagedObject
For å spare litt tid, vi kommer til å besøke Ferdig, programmet vi laget tidligere i denne serien. Last den ned fra GitHub og åpne den i Xcode.
Opprette en NSManagedObject underklasse er veldig enkelt. Selv om det er mulig å lage en NSManagedObject underklasse manuelt for en enhet, er det lettere å la Xcode gjøre jobben for deg.
Åpne datamodell av prosjektet, Done.xcdatamodeld
, og velg Vare
enhet. Velg New > Fil ...
fra Xcode Fil
menyen velger du NSManagedObject underklasse
mal fra kjernedata
delen, og klikk Neste Anmeldelser .
Merk av i boksen av riktig datamodellen, Ferdig
, fra listen over datamodeller og klikk Neste
.
I neste trinn , blir du bedt om å velge de enhetene som du ønsker å opprette en NSManagedObject underklasse. Merk av i boksen for Vare
enhet og klikk Neste
.
Velg et sted å lagre klassen filene i NSManagedObject underklasse og sørg for at Bruk skalar eiendommer for primitive datatyper
er avmerket. Når du arbeider med Objective-C, er dette alternativet en viktig faktor. Men for Swift, er det best å sjekke det som det gjør koden mer lesbar og mindre komplekse. Ikke glem å sette språk til Swift og klikk Opprett
å opprette NSManagedObject underklasse for Vare
enhet.
3. NSManagedObject Anatomy
Naviger til filer Xcode opprettet for deg og ta en titt på innholdet. Xcode skal ha opprette to filer for deg:
Item.swift
Element + CoreDataProperties.swift
Hvis du bruker en tidligere versjon av Xcode, deretter Xcode kan ha skapt bare én fil. Jeg anbefaler å bruke Xcode 7-helst Xcode 7.1 eller høyere for å følge med. Innholdet i Item.swift bør være ganske lett å forstå.
////Item.swift //Ferdig ////Laget av Bart Jacobs på 24/10/15 .//Copyright © 2 015 Envato Tuts +. Alle rettigheter reservert .//import Foundationimport CoreDataclass Sak: NSManagedObject {//Sett inn koden her for å legge til funksjonalitet til din klarte objekt underklasse}
Som du kan se, har Xcode opprettet en klasse for oss, Element, som arver fra NSManagedObject. Kommentaren Xcode har lagt til klassen gjennomføringen er viktig. Hvis du ønsker å legge til funksjonalitet til klassen, bør du legge den til her. La oss nå ta en titt på innholdet i Element + CoreDataProperties.swift.
////Element + CoreDataProperties.swift //Ferdig ////Laget av Bart Jacobs på 24/10/15 .//Copyright © 2 015 Envato Tuts +. Alle rettigheter reservert .////Velg "Opprett NSManagedObject Subclass ..." fra Core data redaktør menyen //slette og gjenskape denne implementeringen filen for den oppdaterte modellen .//import Foundationimport CoreDataextension Element {NSManaged Var createdAt: NSTimeIntervalNSManaged Var gjort: BoolNSManaged Var navn: String}
Det finnes en rekke viktige detaljer og noen nye konsepter. Det første man legger merke til er at denne filen definerer en forlengelse på Element klassen. Utvidelsen erklærer tre egenskaper som samsvarer med attributtene til Element enhet, som vi definerte i datamodellen. DenNSManaged attributtet er lik dendynamic attributtet i Objective-C. DenNSManaged attributtet forteller kompilatoren at lagring og gjennomføringen av disse eiendommene vil bli gitt under kjøring. Selv om dette kan høres flott, Apples dokumentasjon sier klart atNSManaged bør bare brukes i sammenheng med grunndata.
Hvis dette høres litt forvirrende, så husk atNSManaged er nødvendig for kjernedata for å gjøre sitt arbeid ogNSManaged attributtet skal kun brukes til NSManagedObject klasser.
Hva skjer hvis du endrer en enhet og generere filene for foretakets NSManagedObject underklasse igjen? Det er et godt spørsmål, og Xcode advarer deg om dette scenariet. På toppen av Element + CoreDataProperties.swift, under opphavsrett, har Xcode lagt til en kommentar for avklaring.
//Velg "Opprett NSManagedObject Subclass ..." fra Core data redaktør menyen //slette og gjenskape denne implementeringen fil for den oppdaterte modellen.
Når du genererer filene for en enhet, Xcode vil bare erstatte filer av filtypen. Med andre ord, hvis du legger til et attributt til Element enhet og generere filene for NSManagedObject underklasse, Xcode erstatter Element + CoreDataProperties.swift, forlater Item.swift urørt. Det er derfor Xcode ber deg om å legge til funksjonalitet i Item.swift. Dette er veldig viktig å huske på.
De typer eiendommer kan være litt overraskende. Navnet Eiendommen er av typen NSString ?, fordi attributtet er merket som valgfritt i datamodellen. Den createdAt Eiendommen er av typen NSTimeInterval, fordi vi sjekket avkrysnings Bruk skalare eiendommer for primitive datatyper. Det samme gjelder for den gjort eiendom, som er av typen Bool.
Hvis vi ikke hadde sjekket av i boksen, ville createdAt eiendom være av typen NSDate? og gjort eiendommen ville være av typen NSNumber ?. Mens det kan være enklere å bruke NSDate tilfeller er det sikkert mindre praktisk å jobbe med NSNumber gjenstander hvis alt du ønsker er å få og satt boolske verdier.
4. Oppdatere Prosjekt
Med Element klassen klar til bruk, er det på tide å oppdatere prosjektet ved å erstatte eventuelle forekomster av valueForKey (_ :) og SetValue (_:. Forkey :)
ViewController
Åpne gjennomføringen fil av ViewController klassen, navigere til configureCell (_: atIndexPath :), og oppdatere gjennomføringen som vist nedenfor
func configureCell (celle. ToDoCell, atIndexPath indexPath: NSIndexPath) {//Fetch Record la record = fetchedResultsController.objectAtIndexPath (indexPath) som! Sak //Update Cell hvis la name = record.name {cell.nameLabel.text = navn} cell.doneButton.selected = record.done cell.didTapButtonHandler = {record.done =! Record.done}}
Vi har gjort fire endringer. Vi først endret type posten variabel til Element. Den objectAtIndexPath (_ :) metoden i NSFetchedResultsController klassen returnerer en AnyObject eksempel. Men fordi vi vet hentet resultater kontrolleren returnerer et element eksempel vi tvinge nedbrutte resultatet bruker som! operatør.
Vi erstatter også valueForKey (_ :) samtaler. I stedet bruker vi egenskapene til posten objekt, navn og gjort. Takket være Swifts dot syntaks, er veldig leselig resultatet
For å oppdatere posten, vi ikke lenger kalle SetValue (_:. Forkey :). I stedet bruker vi prikken syntaksen til å sette rekord gjøres eiendom. Jeg er sikker på at du enig i at dette er mye mer elegant enn å bruke rett tast verdi koding. Vi trenger heller ikke valgfritt bindende for gjort eiendommen siden gjort Eiendommen er av typen Bool.
Husk at KVC og KVO forbli en integrert del av kjernedata. Kjernen data bruker valueForKey (_ :) og SetValue (_:. Forkey :) under panseret for å få jobben gjort
AddToDoViewController
Vi må også gjøre noen endringer i AddToDoViewController klassen . I spare (_ :) metoden, må vi først å oppdatere initialisering av NSManagedObject eksempel. I stedet for initialisering en NSManagedObject eksempel, skaper vi en Varen eksempel
//Opprett Entitylet enhet = NSEntityDescription.entityForName ("Item", inManagedObjectContext: self.managedObjectContext). //Initial Recordlet record = Element (enhet: enhet !, insertIntoManagedObjectContext : self.managedObjectContext)
For å fylle opp, bruker vi prikken syntaksen i stedet for SetValue (_:. Forkey :) metode som vist nedenfor
//Befolke Recordrecord.name = namerecord.createdAt = NSDate () .timeIntervalSince1970
UpdateToDoViewController
Den siste klassen vi trenger å oppdatere er UpdateToDoViewController klasse. La oss begynne med å endre type posten eiendommen til punkt !.
import UIKitimport CoreDataclass UpdateToDoViewController: UIViewController {IBOutlet svak Var Textfield: UITextField! Var rekord: Element! Var managedObjectContext: NSManagedObjectContext! ...}
Denne endringen vil resultere i en advarsel i ViewController klassen. Å se hva som er galt, åpen ViewController.swift og naviger til prepareForSegue (_:. Avsender :) metode
Vi ber hentet resultater kontrolleren for posten på den valgte indeksen banen. Typen posten variabelen er NSManagedObject, men UpdateToDoViewController klassen forventer et element eksempel. Løsningen er svært enkel som du kan se nedenfor.
Hvis la indexPath = tableView.indexPathForSelectedRow {//Fetch Record la record = fetchedResultsController.objectAtIndexPath (indexPath) som! Sak //Konfigurer View Controller viewController.record = record viewController.managedObjectContext = managedObjectContext}
Leder tilbake til UpdateToDoViewController klassen og oppdatere viewDidLoad () -metoden som vist nedenfor.
Styre func viewDidLoad () {super.viewDidLoad ( ) hvis la name = record.name {textField.text = navn}}
Vi trenger også å oppdatere lagre (_ :) metoden, som erstatter vi SetValue (_:. Forkey :) med prikken syntaks
//Update Recordrecord.name = navn
Bygg prosjektet og kjøre programmet i simulatoren for å se om alt er fortsatt fungerer som forventet.
5. Relasjoner
Den nåværende datamodellen inneholder ingen relasjoner, men la oss legge til noen for å se hvordan en NSManagedObject underklasse med relasjoner ser ut. Som vi har sett i den forrige artikkelen i denne serien, må vi først å lage en ny versjon av datamodellen. Velg datamodellen i Prosjekt Navigator Hotell og velg Legg Model versjon ...
fra Editor
menyen. Sette Version navn
til Ferdig 2 Hotell og basere modellen på dagens datamodell, Ferdig
. Klikk Fullfør
å opprette den nye datamodellen versjon.
Åpne Ferdig 2.xcdatamodel
, opprette en ny enhet som heter Brukeranmeldelser, og legge til en attributt navn
av type String
. Legg et forhold elementer Hotell og satt målet til Vare
. La den inverse forholdet tomt for nå. Med elementer
forholdet valgt, åpner du Data Model Inspektør
på høyre og sette forholdet typen til Slik Mange
. En bruker kan ha mer enn ett element knyttet til dem.
Velg Element
enhet, skape et forhold bruker
, og angi dette som reisemål til User
. Sett inverse forholdet til elementer
. Dette vil automatisk sette den inverse forholdet mellom de elementer
forholdet til Brukeranmeldelser enhet. Merk at brukerforhold er ikke valgfritt.
Før skaper vi NSManagedObject underklasser for begge enhetene, må vi fortelle datamodell som datamodell versjon den skal bruke. Velg Done.xcdatamodeld
, åpne File Inspektør
på høyre side, og sette dagens modell versjon til Ferdig 2
. Når du gjør dette, dobbeltsjekke at du har valgt Done.xcdatamodeld
, ikke Done.xcdatamodel
Velg New >.; Fil ...
fra Fil
menyen og velg NSManagedObject underklasse
mal fra Kjerne data
delen. Fra listen over datamodeller, velg Ferdig 2
.
Velg begge enhetene fra listen over enheter. Fordi vi har endret Element
enhet, trenger vi å regenerere forlengelse for den tilsvarende NSManagedObject underklasse.
Vare
La oss først ta en titt på endringer av nygenererte Sak klasse. Som du kan se nedenfor, utvidelse på Element klasse (Sak + CoreDataProperties.swift) inneholder ett ekstra eiendom, bruker av type Bruker ?.
import Foundationimport CoreDataextension Element {NSManaged Var createdAt: NSTimeIntervalNSManaged Var gjort: Bool NSManaged Var navn: String? NSManaged Var bruker:? Bruker}
Dette er hva en Til En
forhold ser ut i en NSManagedObject underklasse. Xcode er smart nok til å antyde at den type brukeren eiendommen er User ?, den NSManagedObject underklasse vi skapt et øyeblikk siden. Selv om brukerforhold er merket som ikke valgfritt i datamodellen, er den type brukeren eiendommen User ?. Det er ikke klart om dette er tilsiktet eller en feil i Xcode.
Gjennomføringen av Element klasse (Item.swift) er ikke oppdatert med Xcode. Husk at Xcode ikke berører denne filen hvis det allerede eksisterer.
Brukeranmeldelser
Med det vi har lært så langt, er lett å forstå bruksklassen. Ta en titt på forlengelse av User klasse (User + CoreDataProperties.swift). Det første du vil legge merke til er at den type elementer eiendommen er NSSet ?. Dette bør ikke være en overraskelse, fordi vi allerede visste at kjernedata bruker settene forekomster av NSSet klasse, for lagring av medlemmene i en til mange
forholdet. Fordi forholdet er merket som valgfritt i datamodellen, typen er NSSet ?.
import Foundationimport CoreDataextension User {NSManaged Var navn: String? NSManaged Var elementer:? NSSet}
Det er hvor lett det er å jobbe med relasjoner i NSManagedObject klasser
6.. Migrations
Hvis du bygger prosjektet og kjøre programmet i simulatoren, vil du legge merke til at programmet krasjer. Utgangen i Xcode konsoll forteller at datamodellen brukes til å åpne den vedvarende butikken er ikke kompatibel med den som ble brukt til å opprette det. Grunnen til dette problem er forklart i detalj i den tidligere artikkelen i denne serien. Hvis du ønsker å lære mer om vandringer og hvordan du trygt endre datamodellen, så foreslår jeg at du leser den artikkelen.
Konklusjon
subclassing NSManagedObject er veldig vanlig når man jobber med kjernedata. Ikke bare legge den typen sikkerhet, også gjør det å jobbe med relasjoner mye enklere.
I neste utgaven av denne serien tar vi en nærmere titt på kjernedata og samtidighet. Samtidighet er et vanskelig begrep i nesten alle programmeringsspråk, men vet hvilke fallgruver å unngå, gjør det mye mindre skummelt.