Forstå forskjellene mellom Kjernedatamodellen og administrerte objekter

Publisert av donnywals på oktober 5, 2020

Du har kanskje lagt merke til at Når Xcode genererer NSManagedObject – klassene dine basert på kjernedatamodellfilen din, er de fleste egenskapene til det administrerte objektet valgfrie. Selv om Du har gjort dem nødvendige i modellredigeringen, genererer Xcode et administrert objekt der de fleste egenskaper er valgfrie.

I denne artikkelen vil vi utforske dette fenomenet, og hvorfor det skjer.

Utforske genererte nsmanagedobject-underklasser

når du bygger et prosjekt som bruker xcodes automatiske kodegenerering For Kjernedatamodeller, genereres NSManagedObject – underklasser når du bygger prosjektet. Disse klassene er skrevet prosjektets Avledede datamappe, og du bør ikke endre dem direkte. Modellene som genereres Av Xcode, har valgfrie egenskaper for noen av egenskapene du har lagt til i enheten din, uavhengig av om du gjorde egenskapen valgfri i modellredigering.

selv om dette kanskje høres rart ut i begynnelsen, er det faktisk ikke så rart. Ta en titt på følgende NSManagedObject underklasse:

extension ToDoItem { @nonobjc public class func fetchRequest() -> NSFetchRequest<ToDoItem> { return NSFetchRequest<ToDoItem>(entityName: "ToDoItem") } @NSManaged public var completed: Bool @NSManaged public var label: String?}

En av de to egenskapene for min ToDoItem er valgfri, selv om de begge kreves i modelleditoren. Når jeg lager en forekomst av dette ToDoItem, bruker jeg følgende kode:

let item = ToDoItem(context: managedObjectContext)

initialiseringen av et administrert objekt tar en administrert objektkontekst. Dette betyr at jeg ikke tilordner en verdi til de administrerte egenskapene under initialiseringen av ToDoItem. Skrive ut verdien for både egenskapene label og completed gir og interessant resultat:

print(item.label) // nilprint(item.completed) // false

Mens label er nil som forventet, tilordnet Kjernedata en standardverdi på false til completed – egenskapen, noe Som gir mening fordi Xcode genererte en ikke-valgfri egenskap for completed. La oss ta det et skritt videre og ta en titt på følgende kode:

let item = ToDoItem(context: managedObjectContext)item.label = "Hello, item"print(item.label) // "Hello, item"print(item.completed) // falsedo { try managedObjectContext.save()} catch { print(error)}

når du kjører denne koden, finner du at den produserer følgende utdata:

Optional("Hello, item")falseError Domain=NSCocoaErrorDomain Code=1570 "completed is a required value." UserInfo={NSValidationErrorObject=<CoreDataExample.ToDoItem: 0x60000131c910> (entity: ToDoItem; id: 0x600003079900 <x-coredata:///ToDoItem/t1FABF4F1-0EF4-4CE8-863C-A815AA5C42FF2>; data: { completed = nil; label = "Hello, item";}), NSValidationErrorKey=completed, NSLocalizedDescription=completed is a required value.}

denne feilen sier klart completed is a required value. som innebærer at completed ikke er angitt, og det trykte administrerte objektet som vises ved siden av feilmeldingen, viser også at completed er nil. Så mens det er en slags standardverdi til stede for completed, anses den ikke som ikke – nil før den er eksplisitt tildelt.

for å forstå hva som skjer, kan vi tildele en verdi til completed og ta en titt på den trykte beskrivelsen for item igjen:

let item = ToDoItem(context: managedObjectContext)item.label = "Hello, item"print(item.completed)print(item)

denne koden gir følgende utdata:

false<CoreDataExample.ToDoItem: 0x6000038749b0> (entity: ToDoItem; id: 0x600001b576e0 <x-coredata:///ToDoItem/tD27C9C9D-A676-4280-9D7C-A1E154B2AD752>; data: { completed = 0; label = "Hello, item";})

dette er ganske interessant, er Det ikke?

egenskapen completed er definert som en Bool, men den skrives ut som et tall. Vi kan finne årsaken til dette i den underliggende sqlite-butikken. Den enkleste måten å utforske Kjernedatabutikkens sqlite-fil er ved å sende -com.apple.CoreData.SQLDebug 1 som et lanseringsargument til appen din og åpne Sqlite-filen Som Kjernedata kobles til i En Sqlite explorer som sqlite database browser.

Tips:
Lær mer om kjernedatastartargumenter i dette innlegget.

når du ser på skjemadefinisjonen for ZTODOITEM, finner du at den bruker INTEGER som typen for ZCOMPLETED. Dette betyr at egenskapen completed lagres som et heltall i den underliggende sqlite-butikken. Grunnen completed er lagret som en INTEGER er enkel. SQLite har ikke en BOOLEAN – type og bruker en INTEGER – verdi på 0 for å representere false, og 1 for å representere true i stedet.

data som du ser ut når du skriver ut den administrerte objektforekomsten, er ikke verdien for egenskapen completed, men verdien for completed som skal skrives Til sqlite-butikken.

det er to ting å lære av denne delen.

først vet du nå at det er en mismatch mellom opsjonaliteten til den definerte Kjernedatamodellen og de genererte administrerte objektene. En ikke-valgfri String representeres som en valgfri String i den genererte modellen, mens en ikke-valgfri Bool representeres som en ikke-valgfri Bool i den genererte modellen.

For Det Andre lærte du at det er en forskjell mellom hvordan en verdi representeres i den administrerte objektmodellen din, og hvordan den representeres i den underliggende sqlite-butikken. Hvis du vil se hvilke verdier som brukes til å skrive den administrerte objektforekomsten til den underliggende lagringen, kan du skrive ut det administrerte objektet og lese data – feltet i utskriften.

hovedleksjonen her er At Kjernedatamodellen i modellredigeringen og underklassene for administrerte objekter ikke representerer data på samme måte. Valgfritt I Kjernedatamodellen betyr ikke alltid valgfritt i underklassen administrert objekt og omvendt. En ikke-valgfri verdi i Kjernedatamodellen kan representeres som en valgfri verdi i underklassen administrert objekt. Kjernedata vil validere det administrerte objektet mot den administrerte objektmodellen når du prøver å skrive det til det faste lageret og kaste feil hvis det oppstår valideringsfeil.

så hvorfor eksisterer denne mismatchen? Ville det ikke vært mye enklere hvis managed object model og managed object subclasses hadde en direkte tilordning?

Forstå misforholdet mellom administrerte objekter og Kjernedatamodellen

en stor del av grunnen til at det er en mismatch mellom de administrerte objektene og modellen du har definert i modellredigeringen, kommer fra Kjernedatas Objective-C-røtter.

Siden Objective-C ikke håndterer Optional i det hele tatt, er det ikke alltid en god kartlegging fra modelldefinisjonen Til Swift-koden. Ofte virker måten kartleggingen virker noe vilkårlig. For eksempel kan Optional<String> og Optional<Bool> begge ikke representeres som en Type I Objective-C av den enkle grunn at Optional ikke finnes i Objective-C. Swift og Objective-C kan imidlertid interop med hverandre og Optional<String> kan brolegges til en NSString automatisk. Dessverre Optional<Bool> kan ikke tilordnes til noe i Objective-C automatisk som Xcode vil fortelle deg når Du prøver å definere en @NSManaged egenskap som Bool?.

hvis du aldri har jobbet Med Objective-C, kan det virke veldig rart for deg at det ikke er noe konsept av Optional. Hvordan brukte folk valgfrie egenskaper i Kjernedata før Swift? Og hva skjer når noe skal være nil I Objective-C?

I Objective-C er det helt greit for enhver verdi å være nil, selv når du ikke forventer det. Og Siden Kjernedata har sine røtter I Objective-C, overfører noe av denne arven til dine genererte Swift-klasser på en noen ganger mindre enn ideell måte.

Den viktigste takeaway her er ikke hvordan Objective-C fungerer, eller Hvordan Xcode genererer kode nøyaktig. I stedet vil jeg at du skal huske at typene og konfigurasjonen i Kjernedatamodelldefinisjonen din ikke (må) matche typene i din (genererte) administrerte objektunderklasse.

I Sammendraget

i denne ukens artikkel har du lært mye om hvordan underklasser for administrerte objekter og Kjernedatamodelldefinisjon ikke alltid stiller opp slik du forventer at de skal. Du så at noen ganger kan en ikke-valgfri egenskap i modelleditoren ende opp som valgfri i den genererte administrerte objektunderklassen, og andre ganger ender den opp som en ikke-valgfri egenskap med en standardverdi selv om du ikke tildelte en standardverdi selv.

Du så også at hvis en standardverdi er til stede i en forekomst av administrert objekt, betyr det ikke at verdien faktisk er til stede når du lagrer det administrerte objektet, med mindre du eksplisitt har definert en standardverdi i redigeringsprogrammet For Kjernedatamodell.

Selv om Dette er sikkert forvirrende og uheldig, Er Kjernedata ganske gode til å fortelle deg hva som er galt i feilene det kaster mens du lagrer et administrert objekt. Det er også mulig å inspisere verdiene Som Kjernedata vil forsøke å lagre ved å skrive ut den administrerte objektforekomsten og inspisere attributtet data.

På et personlig notat håper jeg at oppførselen jeg beskrev i denne ukens artikkel, er adressert i en fremtidig oppdatering Til Kjernedata som gjør Den Raskere vennlig der de administrerte objektunderklassene har en nærmere, muligens direkte kartlegging Til Kjernedatamodellen som er definert i en modellredigerer. Men inntil da er det viktig å forstå at modellredigereren og dine administrerte objektunderklasser ikke representerer modellen din på samme måte, og at dette i det minste delvis er relatert til Kjernedataens Objective-C-røtter.

hvis du har spørsmål, rettelser eller tilbakemeldinger om dette innlegget vennligst gi Meg beskjed På Twitter. Dette innlegget er en del av noen av forskning, utforskning og forberedelse som jeg gjor for a bestille Om Kjernedata som jeg jobber med. For oppdateringer om denne boken sørg for å følge meg På Twitter. Jeg planlegger for tiden å gi ut boken rundt slutten av 2020.

Hold deg oppdatert med mitt ukentlige nyhetsbrev

Praktisk Kombiner

Lær alt du trenger å vite om Kombiner og hvordan du kan bruke det i dine prosjekter med min Nye bok Praktisk Kombinere. Du får tretten kapitler, En Lekeplass og en håndfull prøveprosjekter for å hjelpe deg med Å komme i Gang med Combine så snart som mulig.

boken er tilgjengelig som en digital nedlasting for bare $29.99!

Få Praktisk Kombinere

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.