Forstå forskellene mellem din Kernedatamodel og administrerede objekter

udgivet af Donny i oktober 5, 2020

du har måske bemærket, at når Kcode genererer dine NSManagedObject klasser baseret på din Kernedatamodelfil, er de fleste af dit administrerede objekts egenskaber valgfri. Selv hvis du har gjort dem påkrævet i modeleditoren, genererer Kcode et administreret objekt, hvor de fleste egenskaber er valgfri.

i denne artikel vil vi undersøge dette fænomen, og hvorfor det sker.

udforskning af genererede NSManagedObject-underklasser

når du bygger et projekt, der bruger Kcode ‘ s automatiske kodegenerering til Kernedatamodeller, genereres dine underklasser NSManagedObject, når du bygger dit projekt. Disse klasser er skrevet dit projekts afledte Datamappe, og du bør ikke ændre dem direkte. De modeller, der genereres af kode, har valgfrie egenskaber for nogle af de egenskaber, du har føjet til din enhed, uanset om du har gjort egenskaben valgfri i modeleditoren.

selvom dette måske lyder underligt i starten, er det faktisk ikke så mærkeligt. Tag et kig 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 af de to egenskaber til min ToDoItem er valgfri, selvom de begge kræves i modeleditoren. Når jeg opretter en forekomst af dette ToDoItem, vil jeg bruge følgende kode:

let item = ToDoItem(context: managedObjectContext)

et administreret objekts initialisering tager en administreret objektkontekst. Det betyder, at jeg ikke tildeler en værdi til de administrerede egenskaber under initialiseringen af ToDoItem. Udskrivning af værdien for både label og completed egenskaber udbytter og interessant resultat:

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

mens label er nil som forventet, tildelte kernedata en standardværdi på false til egenskaben completed, hvilket giver mening, fordi koden genererede en ikke-valgfri egenskab for completed. Lad os tage det et skridt videre og se 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 kører denne kode, vil du opdage, at den producerer følgende output:

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 fejl siger tydeligt completed is a required value., hvilket indebærer, at completed ikke er indstillet, og det udskrevne administrerede objekt, der vises sammen med fejlmeddelelsen, viser også, at completeder nil. Så selvom der er en slags standardværdi til stede for completed, betragtes den ikke som ikke-nil, før den udtrykkeligt er tildelt.

for at forstå, hvad der sker, kan vi tildele en værdi til completed og se på den trykte beskrivelse for item igen:

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

denne kode producerer følgende output:

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

dette er ret interessant, er det ikke?

egenskaben completed er defineret som en Bool, men den udskrives som et tal. Vi kan finde årsagen til dette i den underliggende butik. Den nemmeste måde at udforske din Kernedatabutiks fil er ved at overføre -com.apple.CoreData.SQLDebug 1 som et startargument til din app og åbne den fil, som kernedata opretter forbindelse til i en Stifinder som f.eks.

Tip:
Lær mere om Core Data launch argumenter i dette indlæg.

når du ser på skemadefinitionen for ZTODOITEM, vil du opdage, at den bruger INTEGERsom typen for ZCOMPLETED. Det betyder, at egenskaben completed er gemt som et heltal i den underliggende butik. Årsagen completed er gemt som en INTEGER er enkel. Den har ikke en BOOLEAN type og bruger en INTEGER værdi på 0 til at repræsentere false og 1 til at repræsentere true i stedet.

den data, som du ser udskrevet, når du udskriver din administrerede objektforekomst, er ikke værdien for egenskaben completed, det er værdien for completed, der vil blive skrevet til butikken.

der er to ting at lære af dette afsnit.

først ved du nu, at der er en uoverensstemmelse mellem valgmuligheden for din definerede Kernedatamodel og de genererede administrerede objekter. En ikke-valgfri String er repræsenteret som en valgfri String i din genererede model, mens en ikke-valgfri Bool er repræsenteret som en ikke-valgfri Bool i din genererede model.

for det andet lærte du, at der er forskel på, hvordan en værdi er repræsenteret i din administrerede objektmodel, i forhold til hvordan den er repræsenteret i den underliggende butik. For at se, hvilke værdier der bruges til at skrive din administrerede objektforekomst til det underliggende lager, kan du udskrive det administrerede objekt og læse feltet data i det udskrevne output.

hovedlektionen her er, at din Kernedatamodel i modeleditoren og dine administrerede objekt-underklasser ikke repræsenterer data på samme måde. Valgfri i din Kernedatamodel betyder ikke altid valgfri i underklassen administreret objekt og omvendt. En ikke-valgfri værdi i din Kernedatamodel kan være repræsenteret som en valgfri værdi i underklassen administreret objekt. Kernedata validerer dit administrerede objekt mod dets administrerede objektmodel, når du forsøger at skrive det til den vedvarende butik og smide fejl, hvis det støder på valideringsfejl.

så hvorfor eksisterer denne uoverensstemmelse? Ville det ikke være meget lettere, hvis underklasserne managed object model og managed object havde en direkte kortlægning?

forståelse af uoverensstemmelsen mellem administrerede objekter og Kernedatamodellen

en stor del af grunden til, at der er en uoverensstemmelse mellem dine administrerede objekter og den model, du har defineret i modeleditoren, kommer fra Kernedatas Objective-C-rødder.

da Objective-C ikke beskæftiger sig med Optional overhovedet er der ikke altid en god kortlægning fra modeldefinitionen til hurtig kode. Ofte synes den måde, hvorpå kortlægningen fungerer, noget arbitrat. For eksempel kan Optional<String> og Optional<Bool> begge ikke repræsenteres som en type i Objective-C af den simple grund, at Optional ikke findes i Objective-C. Imidlertid kan hurtig og Objective-C interop med hinanden og Optional<String> kan automatisk Broes til en NSString. Desværre Optional<Bool> kan ikke kortlægges til noget i Objective-C automatisk som kode vil fortælle dig, når du forsøger at definere en @NSManaged egenskab som Bool?.

hvis du aldrig har arbejdet med Objective-C, kan det virke meget mærkeligt for dig, at der ikke er noget begreb Optional. Hvordan brugte folk valgfrie egenskaber i kernedata før Hurtig? Og hvad sker der, når noget skal være nil i Objective-C?

i Objective-C er det helt fint for enhver værdi at være nil, selv når du ikke forventer det. Og da kernedata har sine rødder i Objective-C, overføres noget af denne arv til dine genererede hurtige klasser på en til tider mindre end ideel måde.

den vigtigste afhentning her er ikke, hvordan Objective-C fungerer, eller hvordan kode genererer kode nøjagtigt. I stedet vil jeg have dig til at huske, at typerne og konfigurationen i din Kernedatamodeldefinition ikke (skal) matche typerne i din (genererede) administrerede objekt underklasse.

Sammenfattende

i denne uges artikel har du lært meget om, hvordan dine administrerede objektunderklasser og Kernedatamodeldefinition ikke altid stiller op som du ville forvente dem. Du så, at nogle gange kan en ikke-valgfri egenskab i modeleditoren ende som valgfri i underklassen genereret administreret objekt, og andre gange ender den som en ikke-valgfri egenskab med en standardværdi, selvom du ikke selv tildelte en standardværdi.

du så også, at hvis en standardværdi er til stede på en administreret objektforekomst, betyder det ikke, at værdien faktisk er til stede på det tidspunkt, hvor du gemmer det administrerede objekt, medmindre du eksplicit definerede en standardværdi i Core Data Model editor.

selvom dette bestemt er forvirrende og uheldigt, er kernedata ret gode til at fortælle dig, hvad der er galt i de fejl, det kaster, mens du gemmer et administreret objekt. Det er også muligt at inspicere de værdier, som kernedata vil forsøge at gemme ved at udskrive din administrerede objektforekomst og inspicere dens attribut data.

på en personlig note håber jeg, at den adfærd, jeg beskrev i denne uges artikel, behandles i en fremtidig opdatering til kernedata, der gør det hurtigere venligt, hvor de administrerede objekt-underklasser har en tættere, muligvis direkte kortlægning til Kernedatamodellen, der er defineret i en modeleditor. Men indtil da er det vigtigt at forstå, at modeleditoren og dine administrerede objekt-underklasser ikke repræsenterer din model på samme måde, og at dette i det mindste delvist er relateret til Kernedatas Objective-C-rødder.

hvis du har spørgsmål, rettelser eller feedback om dette indlæg så lad mig det vide på kvidre. Dette indlæg er en del af noget af den forskning, udforskning og forberedelse, som jeg laver til en bog om kernedata, som jeg arbejder på. For opdateringer om denne bog sørg for at følge mig på kvidre. Jeg planlægger i øjeblikket at udgive bogen omkring slutningen af 2020.

Hold dig opdateret med mit ugentlige nyhedsbrev

praktisk mejetærsker

Lær alt hvad du behøver at vide om mejetærsker, og hvordan du kan bruge det i dine projekter med min nye bog Praktisk mejetærsker. Du får tretten kapitler, en legeplads og en håndfuld eksempler på projekter, der hjælper dig med at komme i gang med Combine så hurtigt som muligt.

bogen er tilgængelig som en digital overførsel for kun $29,99!

Få Praktisk Mejetærsker

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.