Core data fra Scratch: Relasjoner og Mer Henter 
 31 
 Del 
 Del 
 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 kalt kjernedata fra Scratch.Core data fra scratch. Managed Objects og Fetch RequestsCore data fra Scratch: NSFetchedResultsController 
 I forrige artikkel, lærte vi om NSManagedObject og hvor enkelt det er å opprette, lese, oppdatere og slette poster ved hjelp av kjernedata. Men det gjorde jeg ikke nevne relasjoner i den diskusjonen. Bortsett fra noen advarsler du må være klar over, relasjoner er like lett å manipulere som attributter. I denne artikkelen vil vi fokusere på relasjoner, og vi vil også fortsette vår utforskning av NSFetchRequest. 
 
 1. Relasjoner 
 
 Vi har allerede jobbet med relasjoner i Core datamodell redaktør og hva jeg skal fortelle deg vil derfor høres kjent. Relasjoner er, akkurat som attributter, nås ved hjelp av nøkkel-verdi koding. Husk at datamodellen vi opprettet tidligere i denne serien definerer en  Person 
 enhet og en  Adresse 
 enhet. En person som er knyttet til en eller flere adresser, og en adresse er knyttet til en eller flere personer. Dette er en  mange-til-mange 
 forholdet 
 
 For å hente adressene til en person, vi bare påberope valueForKey:. På person, en forekomst av NSManagedObject, og pass på adresser som nøkkel. Merk at adresser er nøkkelen vi definert i datamodellen. Hva slags objekt du forvente? De fleste nye til Core data forvente en sortert NSArray, men kjernedata returnerer en NSSet, som usortert. Arbeide med NSSet har sine fordeler som du vil lære senere. 
 
 Opprette Records 
 
Nok med teorien, åpne prosjektet fra forrige artikkel eller klone det fra GitHub. La oss begynne med å lage en person og deretter koble den til en adresse. For å opprette en person, oppdatere programmet: didFinishLaunchingWithOptions: metode som vist nedenfor Anmeldelser - (BOOL) program:. (UIApplication *) applikasjons didFinishLaunchingWithOptions: (NSDictionary *) launchOptions {//Initial Window self.window = [[UIWindow alloc ] initWithFrame: [[UIScreen mainScreen] grenser]]; //Konfigurer Window [self.window setBackgroundColor: [UIColor whiteColor]]; [self.window makeKeyAndVisible]; //Opprett Person NSEntityDescription * entityPerson = [NSEntityDescription entityForName: @ "person" inManagedObjectContext: self.managedObjectContext]; NSManagedObject * newPerson = [[NSManagedObject alloc] initWithEntity: entityPerson insertIntoManagedObjectContext: self.managedObjectContext]; //Set Først og lats Navn [newPerson SetValue: @ "Bart" Forkey: @ "første"]; [newPerson SetValue: @ "Jacobs" Forkey: @ "siste"]; [newPerson SetValue: @ 44 Forkey: @ "age"]; returnere JA;}
 Dette bør se kjent hvis du har lest den forrige artikkelen. Opprette en adresse ligner som du kan se nedenfor 
 //Opprett AddressNSEntityDescription * entityAddress = [NSEntityDescription entityForName: @ "adresse" inManagedObjectContext: self.managedObjectContext];. NSManagedObject * newAddress = [[NSManagedObject alloc] initWithEntity: entityAddress insertIntoManagedObjectContext: self.managedObjectContext]; //Set Først og etternavn [newAddress SetValue: @ "Main Street" Forkey: @ "street"] [newAddress SetValue: @ "Boston" Forkey: @ "by"]; 
 Fordi hver egenskap av  Adresse 
 enhet er markert som  valgfritt 
, trenger vi ikke å tilordne en verdi til hvert attributt. I eksempelet ovenfor, kan vi bare sette rekord er gate- og attributter 
 
 Opprette et forhold 
 
 Hvis du vil koble newAddress til newPerson, påberope vi SetValue. Forkey :, passerer adresser som nøkkel. Verdien som vi passerer i en NSSet som inneholder newAddress. Ta en titt på følgende kodeblokken for avklaring 
 //Legg til adresse til person [newPerson SetValue: [NSSet setWithObject: newAddress] Forkey: @ "adresser"];. //Lagre Managed Object ContextNSError * error = null, hvis (! [newPerson.managedObjectContext sparer: & error]) {NSLog (@ "Kan ikke lagre klarte objekt sammenheng."); NSLog (@ "% @,% @", feil, error.localizedDescription);} 
 Vi kaller spare: på greid objekt sammenheng med newPerson objekt å forplante endringene i vedvarende butikken. Husk at kallet spare: på en administrert objekt sammenheng sparer staten forvaltet objektet sammenheng. Dette betyr at newAddress er også skrevet for å støtte butikken samt relasjonene vi bare definert. 
 
 Du lurer kanskje på hvorfor vi ikke knytte newPerson til newAddress, fordi vi gjorde definere en invers sammenheng i våre data modell. Kjernen data skaper dette forholdet for oss. Hvis et forhold har en invers sammenheng, da kjernedata tar seg av dette automatisk. Du kan kontrollere dette ved å spørre newAddress objekt for sine personer. 
 
 Henter og oppdatere en Relationship 
 
 Oppdatering et forhold er ikke vanskelig heller. Det eneste forbeholdet er at vi må legge til eller fjerne elementer fra uforanderlige NSSet eksempel kjernedata hender til oss. For å gjøre denne oppgaven enklere, men erklærer NSManagedObject en praktisk metode mutableSetValueForKey :, som returnerer en NSMutableSet objekt. Vi kan da bare legge til eller fjerne et element fra samlingen for å oppdatere forholdet. 
 
 Ta en titt på følgende kode blokken der vi skaper en annen adresse, og forbinder det med newPerson. Vi gjør dette ved å påberope mutableSetValueForKey: på newPerson og legge otherAddress til foranderlig sett. Det er ikke nødvendig å fortelle kjernedata som vi har oppdatert forholdet. Kjernen data holder styr på foranderlig sett at det ga oss og oppdaterer forholdet tilsvar 
 //Opprett AddressNSManagedObject * otherAddress = [[NSManagedObject alloc] initWithEntity: entityAddress insertIntoManagedObjectContext: self.managedObjectContext];. //Set Først og etternavn [otherAddress SetValue: @ "5th Avenue" Forkey: @ "street"] [SetValue otherAddress: @ "New York" Forkey: @ "by"]; //Legg til adresse til PersonNSMutableSet * adresser = [newPerson mutableSetValueForKey: @ "adresser "] [adresser addObject: otherAddress]; 
 Slette et forhold 
 
 Slette et forhold er så enkelt som å påkalle SetValue: Forkey :, passerer null som verdien og navnet på forholdet som nøkkelen . Dette unlinks hver adresse fra newPerson 
 //Slett Sivil [newPerson SetValue: nil Forkey: @ "adresser"];. 
 2. En-til-en og en-til-mange relasjoner 
 
 En-til-en-relasjoner 
 
 Selv om vår datamodell ikke definerer et en-til-en-relasjon, har du lært alt du trenger å vite for å jobbe med denne type forhold. Arbeider med en en-til-en forhold er identisk til å samarbeide med attributter. Den eneste forskjellen er at verdien du kommer tilbake fra valueForKey: og verdien du sender til SetValue: Forkey: er en NSManagedObject eksempel 
 
 La oss oppdatere våre datamodell for å illustrere dette.. Åpne  Core_Data.xcdatamodeld Hotell og velg  Person 
 enhet. Opprett et nytt forhold og gi den navnet  ektefelle 
. Sett  Person 
 enhet som destinasjon og sette  ektefelle 
 forhold som den inverse forholdet. 
 
 Som du kan se, er det fullt mulig å skape en relasjon der målet for forholdet er samme enhet som den enhet som definerer forholdet. Merk også at vi alltid satt den inverse av forholdet. Som dokumentasjon statene, er det svært få situasjoner der du ønsker å skape et forhold som ikke har en invers sammenheng. 
 
 Vet du hva som vil skje hvis du skulle bygge og kjøre programmet? Det er riktig, vil programmet krasje. Fordi vi endret datamodellen, den eksisterende butikken, en SQLite database i dette eksempelet, er ikke lenger forenlig med datamodellen. For å bøte på dette, fjerne programmet fra enheten eller iOS Simulator og kjøre programmet. Ikke bekymre deg om, vil vi løse dette problemet mer elegant i en fremtidig avdrag hjelp vandringer. 
 
 Hvis du kan kjøre programmet uten problemer, så er det tid for neste trinn. Head tilbake til programmet delegat klassen og legge til følgende kode blokken 
 //Opprett en PersonNSManagedObject * anotherPerson = [[NSManagedObject alloc] initWithEntity: entityPerson insertIntoManagedObjectContext: self.managedObjectContext];. //Set Først og etternavn [anotherPerson SetValue : @ "Jane" Forkey: @ "første"] [anotherPerson SetValue: @ "Doe" Forkey: @ "siste"] [anotherPerson SetValue: @ 42 Forkey: @ "alder"]; 
 Hvis du vil angi anotherPerson som ektefelle newPerson, vi påberope SetValue: Forkey: på newPerson og passere i anotherPerson og @ "ektefelle" som argumenter. Vi kan oppnå samme resultat ved å påberope SetValue: Forkey: på anotherPerson og bestått i newPerson og @ "ektefelle" som argumenter 
 //Opprett et forhold. [NewPerson SetValue: anotherPerson Forkey: @ "ektefelle"]; 
 En-til-mange relasjoner 
 
 La oss avslutte med en titt på en-til-mange-relasjoner. Åpne  Core_Data.xcdatamodeld 
, velg  Person 
 enhet, og skape en relasjon med navnet  barn 
. Sett reisemålet til  Person 
, angi typen til  Slik Mange 
, og la den inverse forholdet tom for nå. 
 
 Opprett et annet forhold som heter  far 
, angi dette som reisemål til  Person 
, og sette den inverse forholdet til  barn 
. Dette vil automatisk fylle den inverse forholdet mellom  barn 
 forholdet vi tom for et øyeblikk siden. Vi har nå laget en en-til-mange-relasjon, det vil si en far kan ha mange barn, men et barn kan bare ha én far. 
 
 Leder tilbake til programmet delegat og legge til følgende kode blokken . Vi skaper en annen  Person 
 posten, angi attributter, og sett det som et barn av newPerson ved å spørre Kjerne Data for et foranderlig sett for nøkkel barn og legge den nye plata til foranderlig sett. Twitter //Opprett et barn PersonNSManagedObject * newChildPerson = [[NSManagedObject alloc] initWithEntity: entityPerson insertIntoManagedObjectContext: self.managedObjectContext]; //Set Først og etternavn [newChildPerson SetValue: @ "Jim" Forkey: @ "første"] [newChildPerson SetValue: @ "Doe" Forkey: @ "siste"] [newChildPerson SetValue: @ 21 Forkey: @ "age"]; //Opprett RelationshipNSMutableSet * barn = [newPerson mutableSetValueForKey: @ "barn"]; [barn addObject: newChildPerson]; 
 Følgende kode blokk oppnår samme resultat ved å sette far egenskap av anotherChildPerson. Resultatet er at newPerson blir far til anotherChildPerson og anotherChildPerson blir et barn av newPerson 
 //Opprett en Child PersonNSManagedObject * anotherChildPerson = [[NSManagedObject alloc] initWithEntity: entityPerson insertIntoManagedObjectContext: self.managedObjectContext];. //Set Først og etternavn [anotherChildPerson SetValue: @ "Lucy" Forkey: @ "første"] [anotherChildPerson SetValue: @ "Doe" Forkey: @ "siste"] [anotherChildPerson SetValue: @ 19 Forkey: @ "age"]; //Lag Sivil [anotherChildPerson SetValue: newPerson forKeyPath: @ "far"]; 
 3. Mer Henter 
 
 Datamodellen av vår prøveprogrammet har vokst ganske mye i form av kompleksitet. Vi har opprettet en-til-en, en-til-mange og mange-til-mange relasjoner. Vi har sett hvor enkelt det er å lage poster, inkludert relasjoner. Men hvis vi ønsker også å være i stand til å trekke at data fra den vedvarende butikken, så vi trenger å vite mer om henting. La oss starte med et enkelt eksempel der ser vi hvordan å sortere resultatene som returneres av en hente forespørsel. 
 
 Sorter beskrivelsene 
 
 Hvis du vil sortere postene vi får tilbake fra greid objektet sammenheng, bruker vi den NSSortDescriptor klassen. Ta en titt på følgende kodebiten 
 //FetchingNSFetchRequest * fetchRequest = [[NSFetchRequest alloc] initWithEntityName: @ "Person"]; //Legg Sorter DescriptorNSSortDescriptor * sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:. @ "Første" stigende: JA ] [fetchRequest setSortDescriptors: @ [sortDescriptor]]; //Execute Fetch RequestNSError * fetchError = null; NSArray * resultat = [self.managedObjectContext executeFetchRequest: fetchRequest error: & fetchError]; if (! fetchError) {for (NSManagedObject * managedObject i resultat) {NSLog (@ "% @,% @", [managedObject valueForKey: @ "første"], [managedObject valueForKey: @ "siste"]); }} Else {NSLog (@ "Feil ved henting av data."); NSLog (@ "% @,% @", fetchError, fetchError.localizedDescription);} 
 Vi initial en henteforespørsel ved å sende i foretaket som vi er interessert i,  Person 
. Vi deretter opprette en NSSortDescriptor objekt ved å påberope sortDescriptorWithKey: stigende :, bestått i egenskap av foretaket vi ønsker å sortere etter, først, og en boolsk angir om postene må sorteres i stigende eller synkende rekkefølge 
. 
 Vi knytte slags descriptor til hente forespørsel ved å påberope setSortDescriptors: på hente forespørsel, passerer i en matrise som inneholder den typen beskrivelse. Fordi setSortDescriptors: godtar en matrise, er det mulig å passere i mer enn ett slags beskrivelse. Vi vil ta en titt på dette alternativet i et øyeblikk. 
 
 Resten av kodeblokken bør se kjent. Hente forespørselen sendes til den administrerte objektet sammenheng, som utfører hente forespørsel når vi påberope executeFetchRequest: error :. Det er viktig å alltid passere i en peker til et NSError objekt for å vite hva som gikk galt hvis gjennomføringen av hente forespørsel mislykkes. 
 
 Kjør programmet og inspisere produksjonen i Xcode konsoll. Utgangen bør ligne på det som vises nedenfor. Som du kan se, er postene sorteres etter fornavn 
 kjernedata. [1 080: 613] Bart, JacobsCore data [1 080: 613] Jane, DoeCore data [1 080: 613] Jim, DoeCore data [1 080: 613 ] Lucy, Doe 
 Hvis du ser duplikater i produksjonen, så sørg for å kommentere ut koden vi skrev tidligere for å skape postene. Hver gang du kjører programmet, er de samme postene opprettet, noe som resulterer i like poster. 
 
 Som jeg nevnte tidligere, er det mulig å kombinere flere sorterings beskrivelsene. La oss sortere postene ved deres  siste Anmeldelser navn og  alder 
. Vi først sette nøkkelen i den første slags descriptor å vare. Vi deretter opprette en annen slags descriptor med en nøkkel av alder og legge den til i rekke sorterings beskrivelser som vi passerer til setSortDescriptors :. 
 //Legg Sorter DescriptorNSSortDescriptor * sortDescriptor1 = [NSSortDescriptor sortDescriptorWithKey: @ "siste" stigende: YES]; NSSortDescriptor * sortDescriptor2 = [NSSortDescriptor sortDescriptorWithKey: @ "age" stigende: YES] [fetchRequest setSortDescriptors: @ [sortDescriptor1, sortDescriptor2]]; 
 Utgangen viser at rekkefølgen på sorterings beskrivelsene i matrisen er viktig. Postene er først sortert etter deres etternavn og deretter av deres alder 
 kjernedata. [1418: 613] Lucy, Doe (19) Kjerne data [1418: 613] Jim, Doe (21) Kjerne data [1418: 613 ] Jane, Doe (42) Kjerne data [1418: 613] Bart, Jacobs (44) 
 predikater 
 
 Sorter beskrivelsene er stor og lett å bruke, men predikater er det som virkelig gjør henting kraftig i kjernedata . Mens sorterings beskrivelsene forteller kjernedata hvordan postene må sorteres, predikater fortelle den hva registrerer du er interessert i. Den klassen vi skal jobbe med er NSPredicate. 
 
 La oss starte med å hente hvert medlem av Doe familien. Dette er veldig enkelt å gjøre og syntaksen vil minne noen av dere av SQL 
 //FetchingNSFetchRequest * fetchRequest = [[NSFetchRequest alloc] initWithEntityName: @ "Person"]; //Opprett PredicateNSPredicate * predikat = [NSPredicate predicateWithFormat.: @ "% K ==% @", @ "siste", @ "Doe"] [fetchRequest setPredicate: predikat]; //Legg Sorter DescriptorNSSortDescriptor * sortDescriptor1 = [NSSortDescriptor sortDescriptorWithKey: @ "siste" stigende: YES]; NSSortDescriptor * sortDescriptor2 = [NSSortDescriptor sortDescriptorWithKey: @ "age" stigende: YES] [fetchRequest setSortDescriptors: @ [sortDescriptor1, sortDescriptor2]]; //Execute Fetch RequestNSError * fetchError = null; NSArray * resultat = [self.managedObjectContext executeFetchRequest: fetchRequest feil : & fetchError], hvis {for (NSManagedObject * managedObject i resultat) {NSLog (@ "% @,% @", [managedObject valueForKey (fetchError!): @ "første"], [managedObject valueForKey: @ "siste" ]); }} Else {NSLog (@ "Feil ved henting av data."); NSLog (@ "% @,% @", fetchError, fetchError.localizedDescription);} 
 Vi har ikke forandret seg mye bortsett fra å lage en NSPredicate objekt ved å påberope predicateWithFormat: og knytte predikatet til hente forespørsel ved å sende det som et argument for en setPredicate: ring. Ideen bak predicateWithFormat: ligner stringWithFormat: i at den godtar et variabelt antall argumenter 
 
 Merk at predikatet formatstrengen bruker% K for eiendommen navn og% @ for verdien.. Som nevnt i Predicate Programming Guide, er% K en variabel argument erstatning for en nøkkelbanen mens% @ er en variabel argument erstatning for et objekt verdi. Dette betyr at predikatet format streng med vårt eksempel vurderer å vare == "Doe" 
 
 Hvis du kjører programmet en gang til og inspisere produksjonen i Xcode konsollen, bør du se følgende resultat:. 
 kjernedata [1582: 613] Lucy, Doe (19) Kjerne data [1 582: 613] Jim, Doe (21) Kjerne data [1 582: 613] Jane, Doe (42) 
 Det er mange aktører vi kan bruke for sammenligning. I tillegg til = og ==, som er identiske så langt som kjernedata er opptatt av, det er også > = og = >, < = og = >, = og <! ≫, og > og <. Jeg oppfordrer deg til å eksperimentere med disse aktørene for å lære hvordan de påvirker resultatene av hente forespørsel 
 
 Følgende predikat illustrerer hvordan vi kan bruke >. = Operatøren å bare hente Person poster med en alder attributt større enn 30. 
 NSPredicate * predikat = [NSPredicate predicateWithFormat: @ "% K > =% @", @ "alder", @ (30)]; 
 Vi har også operatører for streng sammenligning INNEHOLDER, SOM, KAMPER, BEGINSWITH, og ENDSWITH. La oss hente hver Person posten hvis navn inneholder bokstaven j 
 NSPredicate * predikat =. [NSPredicate predicateWithFormat: @ "% K INNEHOLDER% @", @ "første", @ "j"]; 
 Hvis du kjører søknad nå, vil rekken av resultatene være tom siden strengen sammenligningen er store og små bokstaver som standard. Vi kan endre dette ved å legge til en endrings som så: 
 NSPredicate * predikat = [NSPredicate predicateWithFormat: @ "% K INNEHOLDER [c]% @", @ "første", @ "j"]; 
 Du kan også lage sammensatte predikater ved hjelp av stikkorda AND, OR og NOT. I følgende eksempel, vi hente hver person med fornavn inneholder bokstaven j og er yngre enn 30. 
 NSPredicate * predikat = [NSPredicate predicateWithFormat: @ "% K INNEHOLDER [c]% @ og% K < 30" @ "første", @ "j", @ "alder", @ (30)]; 
 predikater også gjør det svært enkelt å hente poster basert på forholdet deres. . I følgende eksempel, vi hente hver person som fars navn er lik Bart 
 NSPredicate * predikat = [NSPredicate predicateWithFormat: @ "% K ==% @", @ "father.first", @ "Bart"]; 
 Listen predikat fungerer som forventet, fordi% K er en variabel argument erstatning for en  -tasten banen 
, ikke bare en  -tasten 
 
 Hva du trenger. å huske er at predikater gjøre deg i stand til å spørre kompet butikken uten at du vet noe om butikken. Selv om syntaksen til predikatet formatstrengen minner om SQL på noen måter, det spiller ingen rolle om backing butikken er en SQLite database eller en in-memory butikken. Dette er en svært kraftig konsept som ikke er unik for kjernedata. Rails Active Record er et annet godt eksempel på dette paradigmet. 
 
 Det er mye mer å predikater enn det jeg har vist deg i denne artikkelen. Hvis du ønsker å lære mer om predikater, foreslår jeg at du tar en kikk på Apples Predicate Programming Guide. Vi vil også jobbe mer med predikater i de neste artiklene i denne serien. 
 
 Konklusjon 
 
Vi har nå en god forståelse av det grunnleggende kjernedata, og det er på tide å begynne å jobbe med rammeverk ved å lage et program som utnytter sin makt. I neste artikkel, møter vi en annen viktig klasse av Core data rammeverket, NSFetchedResultsController. Denne klassen vil hjelpe oss å administrere en samling av poster, men du vil lære at det gjør ganske mye mer enn det.

