Ydintietomallin ja hallittujen objektien välisten erojen ymmärtäminen

julkaissut donnywals lokakuussa 5, 2020

olet ehkä huomannut, että kun Xcode luo NSManagedObject – luokkasi Ydintietomallitiedostosi perusteella, suurin osa hallinnoidun objektisi ominaisuuksista on valinnaisia. Vaikka olisit tehnyt ne vaadituksi mallieditorissa, Xcode luo hallitun objektin, jossa useimmat ominaisuudet ovat valinnaisia.

tässä artikkelissa tarkastelemme tätä ilmiötä, ja miksi se tapahtuu.

tutkitaan luotuja NSManagedObject-alaluokkia

kun rakennetaan projekti, joka käyttää Xcode-järjestelmän automaattista koodinmuodostusta Ydintietomalleille, NSManagedObject – alaluokat luodaan projektia rakennettaessa. Nämä luokat on kirjoitettu projektisi johdettuun Datakansioon, eikä niitä kannata muokata suoraan. Xcoden luomilla malleilla on valinnaisia ominaisuuksia joillekin ominaisuuksille, jotka olet lisännyt kokonaisuuteesi, riippumatta siitä, Teitkö ominaisuuden valinnaiseksi mallieditorissa.

vaikka tämä saattaa kuulostaa aluksi oudolta, se ei oikeastaan ole niin outoa. Katso seuraava NSManagedObject alaluokka:

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

minun ToDoItem kahdesta ominaisuudesta toinen on valinnainen, vaikka ne molemmat vaaditaan mallieditorissa. Kun luon instanssin tästä ToDoItem, käyttäisin seuraavaa koodia:

let item = ToDoItem(context: managedObjectContext)

hallitun objektin alustaja ottaa hallitun objektin kontekstin. Tämä tarkoittaa, että en anna arvoa hallituille ominaisuuksille ToDoItem: n alustuksen aikana. Sekä label että completed ominaisuuksien arvon Tulostaminen tuottaa ja tuottaa mielenkiintoisen tuloksen:

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

vaikka label on odotetusti nil, ydintietojen oletusarvo false on completed-ominaisuudelle, mikä on järkevää, koska Xcode loi ei-valinnaisen ominaisuuden completed: lle. Otetaan se askel pidemmälle ja katsomaan seuraavaa koodia:

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

kun suoritat tämän koodin, huomaat, että se tuottaa seuraavan tulosteen:

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.}

tämä virhe sanoo selvästi completed is a required value. , mikä tarkoittaa, että completed ei ole asetettu, ja tulostettu hallittu objekti, joka näkyy virheilmoituksen rinnalla, osoittaa myös, että completed on nil. Joten vaikka on olemassa jonkinlainen oletusarvo completed, sitä ei pidetä ei – nil ennen kuin se on eksplisiittisesti määritetty.

ymmärtääksemme mitä tapahtuu, voimme antaa arvon completed ja tarkastella painettua kuvausta item uudelleen:

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

tämä koodi tuottaa seuraavan tulosteen:

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

tämä on aika mielenkiintoista, eikö olekin?

completed ominaisuudeksi on määritelty Bool, mutta se on kuitenkin painettu numerona. Syy löytyy taustalla olevasta SQLite-kaupasta. Helpoin tapa tutkia Core Data Storen SQLite-tiedostoa on ohittaa -com.apple.CoreData.SQLDebug 1 sovelluksen käynnistysargumenttina ja avata SQLite-tiedosto, johon Core Data yhdistyy SQLite explorer-selaimessa, kuten SQLite-tietokantaselaimessa.

Vihje:
Lue lisää keskeisistä tietojen laukaisuargumenteista tässä viestissä.

kun tarkastellaan skeemamääritelmää ZTODOITEM, huomataan, että se käyttää INTEGER tyyppiä ZCOMPLETED. Tämä tarkoittaa, että completed ominaisuus tallennetaan kokonaislukuna taustalla olevaan SQLite-varastoon. Syy completed on tallennettu, koska INTEGER on yksinkertainen. SQLite ei ole BOOLEAN – tyyppiä ja käyttää INTEGER arvoa 0 edustamaan false ja 1 edustamaan true sen sijaan.

data, jonka näet tulostettuna tulostaessasi hallitun objekti-ilmentymän, ei ole completed – ominaisuutesi arvo, vaan completed arvo, joka kirjoitetaan SQLite-kauppaan.

tästä osiosta voi oppia kaksi asiaa.

ensinnäkin tiedät nyt, että määritetyn Ydintietomallisi valinnaisuuden ja luotujen hallittujen objektien välillä on epäsuhta. Ei-valinnainen String esitetään vapaaehtoisena String generoidussa mallissa, kun taas ei-valinnainen Bool esitetään ei-valinnaisena Bool generoidussa mallissa.

toiseksi olet oppinut, että on olemassa ero sen välillä, miten arvo esitetään hallitun objektin mallissa verrattuna siihen, miten se esitetään taustalla olevassa SQLite-kaupassa. Nähdäksesi, mitä arvoja käytetään kirjoitettaessa hallittu objekti-ilmentymä taustalla olevaan tallennustilaan, voit tulostaa hallitun objektin ja lukea data – kentän tulostetusta tulosteesta.

tärkein opetus tässä on se, että mallieditorin Ydintietomallisi ja hallittujen objektien alaluokat eivät edusta dataa samalla tavalla. Valinnainen Ydintietomallissasi ei aina tarkoita valinnaista hallitun objektin alaluokassa ja päinvastoin. Ydintietomallisi ei-valinnainen arvo voidaan esittää valinnaisena arvona hallinnoidun objektin alaluokassa. Ydintiedot validoivat hallitun objektin sen hallitun objektin mallia vastaan, kun yrität kirjoittaa sen pysyvään säilöön ja heittää virheitä, jos se kohtaa validointivirheitä.

joten miksi tämä epäsuhta on olemassa? Eikö olisi paljon helpompaa, jos hallittu objektimalli ja hallittu objekti alaluokat olisi suora kartoitus?

hallittujen objektien ja Ydintietomallin välisen epäsuhteen ymmärtäminen

suuri osa siitä syystä, että hallittujen objektien ja mallieditorissa määrittelemäsi mallin välillä on epäsuhta, tulee Core datan Objective-C-juurista.

koska Objective-C ei käsittele Optional: ää lainkaan, ei mallimääritelmästä Swift-koodiin aina ole hyvää kartoitusta. Usein kartoituksen tekotapa vaikuttaa hieman sattumanvaraiselta. Esimerkiksi Optional<String> ja Optional<Bool> kumpaakaan ei voida esittää tyypinä Objective-C: ssä siitä yksinkertaisesta syystä, että Optional ei ole olemassa Objective-C: ssä.Swift ja Objective-C voivat kuitenkin interopoida keskenään ja Optional<String> voidaan suitsia NSString automaattisesti. Valitettavasti Optional<Bool>: ää ei voi yhdistää mihinkään Objective-C: ssä automaattisesti, Sillä Xcode kertoo, kun yrität määritellä @NSManaged: n ominaisuuden Bool?.

jos et ole koskaan työskennellyt Objective-C: n kanssa, saattaa tuntua hyvin oudolta, ettei Optional: n käsitettä ole olemassa. Miten ihmiset käyttivät valinnaisia ominaisuuksia Core Data ennen Swift? Ja mitä tapahtuu, kun jonkin oletetaan olevan nil Tavoite-C: ssä?

Tavoite-C: ssä on ihan ok, että mikä tahansa arvo on nil, vaikka sitä ei odottaisikaan. Ja koska Core Data on sen juuret Objective-C Jotkut tämän perinnön siirtyy oman syntyy Swift luokat joskus vähemmän kuin ihanteellinen tavalla.

tärkein takeaway tässä ei ole miten Objective-C toimii, tai miten Xcode luo koodia tarkalleen. Sen sijaan haluan sinun muistavan, että Ydintietomallin määritelmän tyypit ja konfiguraatiot eivät (tarvitse) vastaa (generoidun) hallitun objektin alaluokan tyyppejä.

yhteenvedossa

tämän viikon artikkelissa olet oppinut paljon siitä, miten hallitut objektin alaluokat ja Ydintietomallin määrittely eivät aina täsmää odotetulla tavalla. Näit, että joskus ei-valinnainen ominaisuus mallieditorissa voi päätyä valinnaiseksi generoidun hallitun objektin alaluokkaan, ja toisinaan se päätyy ei-valinnaiseksi ominaisuudeksi, jolla on oletusarvo, vaikka et olisi määrittänyt oletusarvoa itse.

näit myös, että jos hallitun objektin ilmentymässä on oletusarvo, se ei tarkoita, että arvo on todella läsnä silloin, kun tallennat hallitun objektin, ellet ole nimenomaisesti määrittänyt oletusarvoa Ydintietomallieditorissa.

vaikka tämä on varmasti hämmentävää ja ikävää, ydintiedot kertovat melko hyvin, mitä vikaa sen heittämissä virheissä on hallittua kohdetta tallennettaessa. On myös mahdollista tarkastaa arvot, joita ydintiedot yrittävät tallentaa tulostamalla hallittu objekti-ilmentymä ja tarkastamalla sen data – attribuutti.

henkilökohtaisesti toivon, että tämän viikon artikkelissa kuvaamaani käyttäytymistä käsitellään tulevassa ydintietojen päivityksessä, joka tekee siitä nopeamman ystävällisen, jossa hallittujen objektien alaluokilla on lähempänä, mahdollisesti suora kartoitus mallieditorissa määriteltyyn Ydintietomalliin. Mutta siihen asti on tärkeää ymmärtää, että mallieditori ja hallittu objekti alaluokat eivät edusta malliasi samalla tavalla, ja että tämä liittyy ainakin osittain Core datan Objective-C-juuriin.

jos sinulla on kysyttävää, korjauksia tai palautetta tästä viestistä, kerro siitä Twitterissä. Tämä viesti on osa joitakin tutkimus, etsintä ja valmistelu, että olen tekemässä kirjaa Ydinaineistoa, että olen työskennellyt. Päivityksiä tästä kirjasta varmista seurata minua Twitterissä. Näillä näkymin aion julkaista kirjan vuoden 2020 lopulla.

Pysy ajan tasalla viikkotiedotteestani

Practical Combine

Opi kaikki, mitä sinun tarvitsee tietää Combinesta ja miten voit käyttää sitä projekteissasi uuden kirjani Practical Combinen avulla. Saat kolmetoista lukua, leikkipaikka ja kourallinen esimerkkiprojekteja, joiden avulla pääset vauhtiin Combinen kanssa mahdollisimman pian.

kirjan saa digitaalisena latauksena vain 29,99 dollarilla!

Get Practical Combine

Vastaa

Sähköpostiosoitettasi ei julkaista.