iPhone Core Data De første trinnene

Kjernedata er et rammeverk Apple gir utviklere som er beskrevet som en "skjema-driven objektgrafikkstyring og persistensramme." Hva betyr det egentlig? Rammeverket håndterer hvor data lagres, hvordan det lagres, data caching og minnehåndtering. Den ble sendt til iPhone fra Mac OS X med 3.0 iPhone SDK-utgivelsen.

I denne opplæringen skal jeg veilede deg gjennom prosessen med å lage et prosjekt med Core Data og vise deg hvordan du bruker det med en enkel UITableViewController. Det vil være en enkel en tabell database som vil lagre Lap Times og vise ganger og deres splitt forskjeller i en UITableView.

Hvorfor bruke Core Data?

Før vi begynner, er det viktig å forstå hvorfor du kanskje vil bruke Core Data med SQLite for lagring over eiendomslister, et tilpasset XML-format eller direkte SQLite-databasetilgang. Core Data API lar utviklere lage og bruke en relasjonsdatabase, utføre postvalidering og utføre spørringer ved hjelp av SQL-mindre forhold. Det gir deg i hovedsak muligheten til å samhandle med SQLite i Objective-C, og trenger ikke å bekymre deg for tilkoblinger eller administrere databaseskjemaet. De fleste av disse funksjonene er kjent for personer som har brukt objektrelasjonell kartlegging (ORM) -teknologi som de som er implementert i Ruby på Rails, CakePHP, LINQ eller andre biblioteker og rammer som abstrakt tilgang til databasen. Hovedfordelen for denne tilnærmingen er at den eliminerer utviklingstiden ellers nødvendig for å skrive komplekse SQL-spørringer og håndtere SQL og utdata fra disse operasjonene manuelt..

Opprette et nytt iPhone-prosjekt med Core Data

Eksempelprogrammet vi skal bygge i dag er en enkel omgangstimer. Det vil skape en ny post i Core Data-butikken for hvert runde vi lager. UITableView vil da vise forskjellen mellom nåværende og siste runder.

For å komme i gang åpner vi XCode og lager et nytt prosjekt. Gi det navnet du ønsker, jeg har kalt det "LapTimer". Vi vil skape en "Window-basert applikasjon" fra det nye prosjektmallvalget. Pass på at "Bruk kjernedata for lagring" er merket.

Prosjektet bør være kjent med det du måtte ha sett før hvis du tidligere har utviklet iPhone-applikasjoner.

Sette opp Core Data Structure

Det er ikke mye å gjøre som alternativet "Bruk kjernedata for lagring" i "Window-based Application" -malen har automatisk satt noen viktige variabler og opprettet filer i prosjektet for oss.

LapTimer.xcdatamodel-filen er der vi skal definere skjemaet for SQLite-databasen vår. Kjernedata-rammen ble også lagt til prosjektet for å inkludere filene for API-tilgang. De andre endringene gjøres innenfor standard applikasjonsfiler. I særdeleshet har programdelegasjonsfilene metodene for å sette opp Core Data-butikken i vår søknad og å referere det til barn UIViewControllers.

Det vi er interessert i for øyeblikket, er LapTimer.xcdatamodel-filen under "Ressurser". Denne filen gir deg et visuelt kart over skjemaet ditt som viser enheter og attributter.

Det finnes noen forskjellige termer og uttrykk som brukes i Core Data, som kan løst relateres til vanlige databasenavn, men de er ikke identiske.

En "enhet", også kjent som et "administrert objekt", ligner på et bord. Det er en definisjon av et objekt som vil inneholde en samling av data. En entitetsobjekt inneholder "attributter". Disse kan være løst knyttet til kolonner, men disse egenskapene er ikke bare begrenset til datalagring. Attributter kan definere et forhold mellom to enheter, en dynamisk hentet eiendom, eller definere en egenskap for datalagring.

Fra diagrammet ovenfor kan du få en følelse av hvordan fleksible objekter avledet fra Core Data-enheter er. For dette eksempelet søknaden trenger vi en veldig enkel enhet. Vi vil ringe enheten "Event" som vil lagre poster av våre runder.

Hva vi skal gjøre for å opprette denne enheten, klikker du på [+] -knappen i den første (fra venstre) øvre kolonne. Dette vil opprette en ny enhet i listen og visuelt på skjemarkartet under kolonnene.

Dette er en fin visuell editor for din modell. Kjernedata gjør det virkelig tungt når det gjelder "M" (modell) del av MVC. Den visuelle redaktøren viser forholdene, egenskapene og enhetene i butikken mens skjemaet er dynamisk opprettet og administrert alt for deg. Dette ligner på Interface Builder, da det tar seg av å tildele, administrere og plassere objekter for deg på en UIView uten en enkelt linje med kode.

Med den nye Event-enheten på plass, ønsker vi å opprette en "eiendom". Siden denne egenskapen vil lagre data, vil vi sette den som en "attributt". Så dette nye attributtet lagrer bare gjeldende dato for når posten ble opprettet. I vår eksempelapplikasjon vil vi bruke dette til å referere til våre runde ganger.

Neste kolonne til høyre er hvor vi definerer våre egenskaper (pass på at Event-enheten er valgt). Så opprett en ny eiendom ved hjelp av [+] -knappen i kolonnen, velg "Legg til attribut".

Vi kaller attributten "timeStamp" og setter sin Type til "Date". I rullegardinmenyen velger du de samme kolonnedatatypene som de som er tilgjengelige i relasjonsdatasystemer som PostgreSQL eller MySQL, inkludert datatyper som heltall, floats, strenger, booleans, datoer og binære data (blobs).

For dette attributtet trenger vi ikke andre alternativer valgt eller endret.

Det er det for xcdatamodel-filen, og vi kan flytte på å integrere den i vår app. Nå er det en god tid å redde arbeidet ditt.

Opprette våre modellfiler

Hvis du har brukt et MVC-rammeverk som har definisjoner av databasemodeller som definerer et bords struktur eller atferd, så vil dette være en kjent oppgave.

Vi må starte med å skape en definisjon av enheten. Vi gjør dette ved å opprette en NSManagedObject-klasse av enheten og definere variablene butikken har.

Dette er en enkel prosess. Velg hendelsesenheten i filen LapTimer.xcdatamodel, og gå til Fil> Ny fil. Du vil se at det er en ny filmal i "Cocoa Touch Class" delen "Managed Object Class".

Velg malen og trykk "Neste". Den neste skjermen er bare å definere hvor vi lagrer filen og målet for å inkludere det med, dette er alt riktig som standard, så trykk "Neste" igjen. Neste skjermbilde er hvor du definerer hvilke enheter du vil lage NSManagedObject-klasser for. Hvis det ikke er valgt, velg Event og sørg for at avmerkingsboksene "Generer Accessors" og "Generate Obj-C 2.0 Properties" er valgt, vi trenger ikke valideringer for øyeblikket. Hit Finish.

Så nå har vi 2 nye filer i vår søknad. Event.m og Event.h. De definerer klassen NSManagedObject for Event-enheten som vi opprettet i vår Core Data-butikk. De definerer timeStamp-feltet, så når vi vil bruke hendelsesklassen, kan vi få tilgang til attributtet.

Event.h

 #importere  @interface Event: NSManagedObject  @property (nonatomic, behold) NSDate * timeStamp; @slutt 

Event.m

 #import "Event.h" @implementation Event @dynamic timeStamp; @slutt 

Som modelldefinisjoner i andre rammer og språk kan du legge til tilpassede metoder for alle poster i Event-enheten. Du vil legge merke til at timeStamp-attributtet er lagt til og tilordnet som et NSDate-objekt.

Kjernedata og KVC

Med Core Data setup er det nå på tide å jobbe med noen av kontrollerlogikken i applikasjonen. Vi vil bruke en UITableViewController som hovedgrensesnittet for appen for å vise rundetider, samt logge en ny tid.

Så, vi vil opprette den nye UITableViewController med File> New File. Deretter velger du "UIViewController subclass" under iPhone-delen og kontrollerer "UITableViewController-underklasse", men ikke merker av bokser som vedrører bruk av XIB-er eller for målretting for en iPad. Vi vil ikke bruke en XIB for denne kontrolleren. Ring den nye filen "TimeTableController" og avslutt filveiviseren.

I denne kontrolleren trenger vi 2 egenskaper, en referanse til NSManagedObjectContext og en matrise for å lagre postene for UITableView. I tillegg til å definere egenskapene, importerer vi Event.h filen, slik at vi kan bruke klassen.

TimeTableController.h

 #importere  #import "Event.h" @interface TimeTableController: UITableViewController NSManagedObjectContext * managedObjectContext; NSMutableArray * eventArray;  @property (nonatomic, behold) NSManagedObjectContext * managedObjectContext; @property (nonatomic, behold) NSMutableArray * eventArray; - (void) fetchRecords; - (void) addTime: (id) avsender; @slutt 

Hva er en NSManagedObjectContext? Det refereres til som "skrapelodd" for kjerne data i programmet for å administrere henting, oppdatering og opprett poster i butikken. Den administrerer også noen få grunnleggende funksjoner i Core Data, inkludert valideringer og angre / gjenta administrasjon for postene.

Konteksten for administrert objekt er sammenhengen mellom koden og databutikken. Alle operasjonene du vil utføre for Core Data gjør det mot konteksten for administrert objekt. Når en forespørsel blir utført, vil konteksten for administrert objekt deretter snakke med den vedvarende butikkoordinatoren som er ansvarlig for å kartlegge objektene til data for datalageret. Dette gjør at Core Data kan være fleksibel mellom ulike datalagerformater. Her er et diagram over hvordan dette ser ut.

Med overskriftsfilen definert må vi forplante de tildelte egenskapene og metodene i implementeringsfilen.

TimeTableController.m

 #import "TimeTableController.h" @implementation TimeTableController @synthesize managedObjectContext, eventArray; // ... // ... standard kommentert kode fra filmalen // ... - (void) viewDidLoad [super viewDidLoad]; self.title = @ "Lap Times"; UIBarButtonItem * addButton = [[UIBarButtonItem alloker] initWithBarButtonSystemItem: UIBarButtonSystemItemAdd mål: self action: @selector (addTime :)]; self.navigationItem.rightBarButtonItem = addButton; [addButton release]; [selvfetchRecords];  - (void) addTime: (id) avsender Event * event = (Event *) [NSEntityDescription insertNewObjectForEntityForName: @ "Event" inManagedObjectContext: managedObjectContext]; [event setTimeStamp: [NSDate date]]; NSError * feil; hvis (! [managedObjectContext save: & error]) // Dette er en alvorlig feil som sier at posten // ikke kunne lagres. Gi brukeren beskjed om å // prøve på nytt eller start programmet på nytt.  [eventArray insertObject: event atIndex: 0]; [self.tableView reloadData];  - (void) fetchRecords // Definer vårt bord / enhet for å bruke NSEntityDescription * entity = [NSEntityDescription entityForName: @ "Event" inManagedObjectContext: managedObjectContext]; // Oppsett hent-forespørselen NSFetchRequest * request = [[NSFetchRequest alloc] init]; [be om setEntity: entity]; // Definer hvordan vi vil sortere postene NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey: @ "timeStamp" stigende: NO]; NSArray * sortDescriptors = [NSArray arrayWithObject: sortDescriptor]; [request setSortDescriptors: sortDescriptors]; [sortDescriptor release]; // Hent oppføringene og håndter en feil NSError * feil; NSMutableArray * mutableFetchResults = [[managedObjectContext executeFetchRequest: forespørselfeil: & feil] mutableCopy]; hvis (! mutableFetchResults) // Håndter feilen. // Dette er en alvorlig feil og bør gi brukeren beskjed om å starte programmet på nytt // Lagre våre hentede data i en rekkefølge [self setEventArray: mutableFetchResults]; [mutableFetchResults release]; [be om utgivelse];  // ... // ... flere malkommentarer og standardmetodedefinisjoner // ... - (void) dealloc [managedObjectContext release]; [eventArray-utgivelse]; [super dealloc];  @slutt 

Det er en god del kode slik at vi kan gå gjennom det ved hver metode individuelt. Det er kode fra når du lager filen fra malen, kommenterte metoder som viewDidUnload, som jeg nettopp har utelatt fra ovenstående.

viewDidLoad

Vi starter med det vanlige samtalen til superklassen. Deretter definerer vi UINavigationBars tittel. Deretter må vi definere knappen vi vil bruke til å legge til en post i Core Data-butikken. Når du trykker på knappen, forteller vi at den skal ringe til selgeren addTime: som vil da samhandle med Core Data. Etter de nødvendige utgivelsene kommer vi til å ringe funksjonen fetchRecords som forklares nedenfor.

addTime: (id) avsender

Dette avfyres når UIBarButtonItem øverst til høyre i UINavigationBar er trykket. Vi må opprette en ny Event-post med gjeldende NSDate og lagre den i databasen.

Vi lager en ny Event-post som heter NSEntityDescription. Dette er din rad i databasen for den nye posten. For å gjøre dette definerer vi entitetenavnet posten tilhører og gir NSManagedObjectContext. Nåværende dato er da satt mot timeStamp attributtet.

Lagringsoperasjonen utføres da, men det er en bestemmelse om å håndtere en feil hvis innsatsen mislykkes. Du vil vanligvis kaste en UIAlertView som sier at posten ikke opprettet, og kanskje instruere brukeren om å prøve igjen eller lukke og åpne applikasjonen igjen.

Rekordet må legges til matrisen som UITableView feeds fra. Da må UITableView bli fortalt å laste dataene på nytt. Du kan gjøre dette mer grafisk med en animasjon, men for tutorialets skyld, la oss holde det enkelt.

fetchData

Denne metoden vil hente dataene fra butikken og legge den til i gruppen vi har i kontrolleren. For ytterligere detaljer om å få poster, la oss ta en nærmere titt på NSFetchRequest.

Henter data fra datalageret

Core Data har en annen tilnærming til å hente data fra databasen. Det er en NoSQL datalager, noe som betyr at alle betingelsene for en spørring er basert på metoder. Dette er bra da base-butikken, som er SQLite, kan endres til hvilken som helst annen databaseteknologi, og det eneste som skal endres, er forbindelsen og drivere for databasen.

Så, for å lage en forespørsel, oppretter vi et NSFetchRequest-objekt. Dette er basisobjektet som spørringsbetingelsene vil bli satt til. Vi kan definere betingelser for å matche en bestemt eiendom basert på hvordan poster blir bestilt. Du kan finne ut mer om Core Data og vilkårene for NSFetchRequests i dokumentasjonen.

Å lage en ny NSFetch-forespørsel er enkel. Du trenger bare å definere enheten du vil ha poster fra og NSManagedObjectContext.

 NSEntityDescription * entity = [NSEntityDescription entityForName: @ "Event" inManagedObjectContext: managedObjectContext]; NSFetchRequest * request = [[NSFetchRequest alloker] init]; [be om setEntity: entity]; 

Enheten er definert ved hjelp av et NSEntityDescription-objekt som krever enhetens navn og NSManagedObjectContext. Hentforespørselen opprettes da ved å passere enhetens beskrivelse. Dette ville tilsvare den første delen av en SQL-setning:

 SELECT * FROM 'events' 

I vår eksempelapplikasjon sorterer vi dataene etter tidsstempelet på avtagende måte. For å gjøre dette bruker vi en NSSortDescriptor.

 NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey: @ "timeStamp" stigende: NO]; NSArray * sortDescriptors = [NSArray arrayWithObject: sortDescriptor]; [request setSortDescriptors: sortDescriptors]; [sortDescriptor release]; 

NSSortDescriptor er opprettet, og vi definerer attributtet vi ønsker å sortere og hvorvidt det stiger, i dette tilfellet vil vi at den skal synke slik at den er satt til NO. Hentforespørselen kan ta mange sorteringsbeskrivere, slik at den aksepterer en matrise når du angir sorteringsbeskrivelsene. Siden vi bare vil ha en, trenger vi bare å lage en matrise med ett objekt i den. Vi angir beskrivelsesarrangementet mot henting-forespørselen, og det er det.

For å definere en betingelse for å matche et arkivinnhold, kommer NSPredicate-klassen til å spille. Det gjør det mulig å hente forespørselen sammen, eller definere et område som innholdet i en plate må møte. Dette er ekvivalentet med dine likeverdige, større og mindre enn samsvarer i SQL. Den har mer enn de grunnleggende SQL-funksjonene, som du kan se her.

Innstilling av et predikat kan være veldig enkelt.

 NSPredicate * predicate = [NSPredicate predicateWithFormat: @ "(siste navn som% @) OG (bursdag>% @)", lastNameSearchString, birthdaySearchDate]; 

Bruke NSPredicate predicateWithFormat: er en enkel og kjent metode som lar deg definere betingelsene for spørringen. For en grundig forklaring på NSPredicates har Apple Documentation noen gode guider.

Når du har definert betingelsene i din forespørselsforespørsel, kan du deretter utføre den.

 NSMutableArray * mutableFetchResults = [[managedObjectContext executeFetchRequest: forespørselfeil: & feil] mutableCopy]; 

Det vil returnere en rekke enheterobjekter, NSManagedObjects, til bruk i datautgangen.

Populere UITableView fra Core Data

Med data hentet fra Core Data og lagret i eventArray kan vi nå utføre disse postene i UITableView.

Første ting er å fortelle bordet at vi bare trenger 1 del og hvor mange rader vi må bruke.

Utdrag fra TimeTableController.m

 -(NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return 1;  - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) seksjon return [eventArray count];  

Hvis du har brukt en UITableViewController før, bør neste funksjon være rett fram.

 -(UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath statisk NSString * CellIdentifier = @ "Cell"; statisk NSDateFormatter * dateFormatter = null; hvis (dateFormatter == nil) dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat: @ "h: mm.ss a"];  UITableViewCell * celle = [tableView dequeueReusableCellWithIdentifier: CellIdentifier]; hvis (celle == nil) celle = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: CellIdentifier] autorelease];  Event * event = [eventArray objectAtIndex: [indexPath row]]; Hendelse * previousEvent = null; hvis ([eventArray count]> ([indexPath row] + 1)) previousEvent = [eventArray objectAtIndex: ([indexPath row] + 1)];  [cell.textLabel setText: [dateFormatter stringFromDate: [event timeStamp]]]; if (previousEvent) NSTimeInterval timeDifference = [[event timeStamp] timeIntervalSinceDate: [forrige timeStamp]]; [cell.detailTextLabel setText: [NSString stringWithFormat: @ "+%. 02f sec", timeDifference]];  else [cell.detailTextLabel setText: @ "---"];  returcelle;  

Cellen vil vise 2 verdier, fra å bruke formatet UITableViewCellStyleValue1. Venstre blir klokkeslettet, og høyre vil være forskjellen i sekunder fra forrige plate.

Siden denne metoden iterates må vi være spesielt forsiktige med belastningen den kan sette enheten under hvis den ikke styres riktig. Derfor er NSDatFormatter lagret som en statisk variabel slik at den kan gjenbrukes i hver iterasjon uten å tildele og slippe den hver gang.

Lazy Loading

Lazy Loading er en teknikk hvor du forsinker forespørselen eller tildelingen av en eiendom så mye som mulig. Dette bidrar til å holde minnet nede og under iterative funksjoner er dette avgjørende. Å vite når og hvordan å tildele data er avgjørende for å holde en mobilapp rask. Deallokering av objektet er også like viktig, jo tidligere jo bedre.

cellForRowAtIndexPath: er en iterativ metode, og data som behandles eller allokert i denne metoden, må spesielt holdes på et minimum. Denne metoden kjøres når en celle kommer til syne, så når en bruker ruller raskt, kan denne metoden, avhengig av rekordstørrelsen, kalles svært ofte i rekkefølge.

Den neste oppgaven er å få hendelsesobjektet knyttet til tabellraden som må gjengis. Siden vi trenger å få den forrige posten for tidssammenligningen, er det en enkel sjekk for å se om det er en tidligere post og å lagre den i tidligereEvent. Hvis foregåendeEvent eksisterer, beregner vi splitten ved hjelp av [NSDate timeIntervalSinceDate: (NSDate)]. TextLabel og DetailedTextLabel settes deretter med verdiene som vi har beregnet.

Etterbehandling av søknaden

Med UITableViewController-oppsettet og tabelldatakilden som arbeider med Core Data-butikken, er alt som trengs for å laste inn kontrolleren når programmet startes.

I Programkontrolleren må en UINavigationController-egenskap defineres. Da må ApplicationDidFinishLaunching-metoden bare tilordne kontrolleren og vi er ferdige.

LapTimerAppDelegate.h

 @interface LapTimerAppDelegate: NSObject  NSManagedObjectModel * managedObjectModel; NSManagedObjectContext * managedObjectContext; NSPersistentStoreCoordinator * persistentStoreCoordinator; UIWindow * vindu; UINavigationController * navigationController;  @property (nonatomic, behold, readonly) NSManagedObjectModel * managedObjectModel; @property (nonatomic, behold, readonly) NSManagedObjectContext * managedObjectContext; @property (nonatomic, behold, readonly) NSPersistentStoreCoordinator * persistentStoreCoordinator; @property (nonatomic, behold) IBOutlet UIWindow * vindu; @property (nonatomic, behold) UINavigationController * navigationController; - (NSString *) applicationDocumentsDirectory; @slutt 

Utdrag fra LapTimerAppDelegate.m

 #import "LapTimerAppDelegate.h" #import "TimeTableController.h" @implementation LapTimerAppDelegate @synthesize vindu, navigationController; - (ugyldig) applicationDidFinishLaunching: (UIApplication *) søknad TimeTableController * tableController = [[TimeTableController alloker] initWithStyle: UITableViewStylePlain]; tableController.managedObjectContext = [self managedObjectContext]; self.navigationController = [[UINavigationController alloc] initWithRootViewController: tableController]; [tableController release]; [window addSubview: [self.navigationController view]]; [window makeKeyAndVisible];  // ... // ... andre malmetoder // ... - (void) dealloc [managedObjectContext release]; [managedObjectModel release]; [persistentStoreCoordinator release]; [vindu utgivelse]; [navigeringskontroller utgivelse]; [super dealloc];  

TimeTableController.h filen er inkludert i programdelegatet og deretter tildelt med en UINavigationController.

Det burde være det. Bygg applikasjonen for å se etter feil. Noen av kodeeksemplene har bare blitt ekstrakter, ingen av kodene som genereres når en fil er slettet, er bare fylt ut. Hvis du får feil i det du ikke kan sprekke, kan du laste ned prosjektfilen som er vedlagt denne opplæringen som du deretter kan kompilere og sammenligne.

Kjør programmet. Du vil se navigasjonskontrollen og tilleggsknappen. Trykk på add-knappen, og du får en ny tid i bordet.

oppsummering

I denne opplæringen har vi laget et eksempelprogram for å lagre enkle data i en Core Data-butikk. Søknaden løp gjennom den første oppsettprosedyren når du oppretter et program med Core Data, definerer datastrukturen og henter poster fra datalageret.

Forhåpentligvis har du fått en introduksjon til Core Data, og kan se hvor lett det er å bruke og hvordan det kan forbedre programmets ytelse og funksjonalitet.

Hvis du vil finne ut mer om Core Data eller ønsker en detaljert titt på rammens struktur, er Apple Developer Documentation det perfekte stedet å gå.

ressurser

Apple Developer Documentation:

Introduksjon til Core Data Programming

Core Data Migration and Versioning

NSPredicate Programmeringsveiledning: