Werken met kerngegevens schemareversies en lichtgewichtmigraties

Na het lezen van Eerste stappen met Core Data, zijn we op de hoogte van de manier waarop Core Data werkt en hoe het ons kan helpen data-rijke applicaties te ontwikkelen. Het oppervlak was echter nog maar net bekrast en in sommige toepassingen kunt u zich afvragen hoe u een bepaald stuk functionaliteit kunt implementeren.

Mijn ervaring met kerngegevens

De afgelopen maanden heb ik met Core Data aan een huisdierenproject gewerkt. Het is een toepassing om gegevens van een API voor externe services op te halen, de gegevens op te slaan in kerngegevens en deze weer te geven in een verzameling UITableViews. In de loop van de ontwikkeling is het gegaan van een op een op eigendommenlijst gebaseerde gegevensopslag (* shudder *) naar een Core Data SQL-winkel. Na drie complete herbouwingen en vele lange nachten debuggen, is mijn applicatie eindelijk een snel, crashvrij en geheugenlekvrij project geworden. Voor mij heeft het gebruik van Core Data mijn toepassing gemaakt tot wat het was bedoeld en ik deel veel van wat ik heb geleerd met u in deze en toekomstige artikelen.

Voor dit artikel zullen we voortbouwen op de vorige LapTimer-toepassing en aantonen dat we lichtgewicht migraties uitvoeren.

Wijzigingen in het schema, versies en migraties

Wanneer u een toepassing aan het ontwikkelen bent, zult u het schema bijna nooit helemaal goed krijgen. Dus Core Data heeft ondersteuning voor schemaversionering en datamigratie. Hiermee kunt u een nieuwe versie van het Core Data-schema definiëren door een nieuw attribuut of een nieuwe entiteit aan de store toe te voegen. Definieer vervolgens hoe de winkel van de ene wijziging naar de andere moet migreren.

Een nieuw xcdatamodel maken

Core Data verwerkt schemaversies anders dan sommige andere frameworks die u in het verleden wellicht hebt gebruikt. Wanneer u de ontwikkeling doorloopt en een nieuw attribuut of een nieuwe entiteit nodig heeft, kunt u deze toevoegen door een nieuw xcdatamodel-bestand voor uw toepassing te maken. Dit nieuwe bestand zal een versienummer hebben, een incrementeel nummer hebben in de bestandsnaam en verschilt van oudere schemaversies. Maak in de LapTimer-applicatie de nieuwe datamodel-versie. Klik op het xcdatamodel-bestand in uw toepassing en navigeer vervolgens naar het menu-item op: Ontwerp> Gegevensmodel> Modelversie toevoegen.

U krijgt nu een xcdatamodelboom, waarvan de bovenliggende een nieuw xcdatamodel-bestand is, met een nieuwe schemaversie die wordt aangeduid met het incrementele nummer. Ook is er een groen vinkje tegen het oude schema. Dit geeft aan welk schema actief is en welke toepassing het zal gebruiken. Het is belangrijk om te weten dat het direct kiezen van de nieuwe versie problemen kan veroorzaken. Omdat we nog geen migratie voor dit nieuwe schema hebben ingesteld, zullen we, als we het nieuwe schema het actieve schema zouden maken, de Simulator of het apparaat een foutmelding geven en bij het opstarten crashen. Als een demonstratie, kijk eens naar de onderstaande fout, het is gebruikelijk voor wat mensen tegenkomen bij hun eerste poging:

Het zegt eigenlijk alleen maar: "Hé, je hebt het actieve DB-schema gewijzigd en ik zit vast aan een oudere versie." Hiermee voorkomt u dat de toepassing conflicteert en fouten maakt met wijzigingen in het Core Data-winkelschema. Er wordt een vergelijking gemaakt op basis van de details van het schema waarmee de winkel werkt. Als het een nieuwe schemaversie wordt gegeven om te gebruiken, maar het komt niet overeen met wat het is ingesteld of gemigreerd naar, dan krijg je deze foutmelding.

Dus, hoe komen we hier voorbij? Welnu, er zijn twee opties:

  1. Als de app in ontwikkeling is en u zich geen zorgen maakt over gegevens in de toepassing, verwijdert u de toepassing gewoon van het apparaat en installeert u deze opnieuw. Het verwijdert de winkel en de inhoud ervan, maar het maakt de app met het nieuwe schema. Dit is slechts een optie in ontwikkeling.
  2. Gebruik lichtgewichtmigratie om automatisch voor kleine wijzigingen in het schema te zorgen wanneer u ze maakt. Dit is beperkt tot slechts enkele migraties die hieronder worden beschreven.

Lichtgewicht migratie

Dit is een eenvoudig te gebruiken en een automatisch kenmerk van Core Data, maar het is beperkt tot alleen eenvoudige migraties, vandaar de reden dat het lichtgewicht is. U kunt deze methode alleen gebruiken als de wijzigingen een van de volgende zijn:

  • Een nieuw kenmerk / eigenschap toevoegen aan een entiteit.
  • Hernoemen van een entiteit of een attribuut / eigenschap als de 'Renaming Identifier' wordt gegeven.
  • Een kenmerk / eigenschap wijzigen in optioneel of niet-optioneel, of het bij het maken een waarde vereist.

Opmerking: Voordat we duiken, moet je het project bouwen voordat we beginnen als je aan het LapTimer-project werkt. Zorg ervoor dat het actieve xcdatamodel de eerste versie is waarmee de applicatie is gebouwd. Op deze manier kunt u de migratie zien werken.

Als demonstratie zal de LapTimer-applicatie de gebeurtenisentiteit laten veranderen in Lap. Hiermee moeten we ook de klassen Event.h en Event.m en eventuele gevallen in de toepassing bijwerken. Met een paar handige Xcode-functies is dit pijnloos.

Dus in de nieuwe versie van het xcdatamodel dat we eerder hebben gemaakt, ga ik de wijziging aanbrengen door simpelweg de waarden in het deelvenster met entiteitdetails te wijzigen. Nu moeten we de 'Renaming Identifier' op Evenement zetten. Dus klik in hetzelfde paneel op de sleutel / sleutel en voer "Gebeurtenis" in het veld Identificatie hernoemen, zoals:

De volgende stap is om Core Data te laten weten dat het lichtgewicht migraties tijdens het opstarten kan uitvoeren. Verwijzend naar de LapTimer-toepassing, in het LapTimerAppDelegate.m-bestand, moeten we een code toevoegen aan de - (NSPersistentStoreCoordinator *) persistentStoreCoordinator-methode:

 - (NSPersistentStoreCoordinator *) persistentStoreCoordinator if (persistentStoreCoordinator! = Nil) return persistentStoreCoordinator;  NSURL * storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @ "LapTimer.sqlite"]]; NSError * error = nil; persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool: YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool: YES], NSInferMappingModelAutomaticallyOption, nil]; if (! [persistentStoreCoordinator addPersistentStoreWithType: NSSQLiteStoreType-configuratie: nil URL: storeUrl-opties: options error: & error]) / * Vervang deze implementatie door code om de fout op de juiste manier af te handelen. abort () zorgt ervoor dat de applicatie een crashlogboek genereert en eindigt. Gebruik deze functie niet in een verzendapplicatie, hoewel het nuttig kan zijn tijdens de ontwikkeling. Als het niet mogelijk is om de fout te herstellen, geeft u een waarschuwingsvenster weer dat de gebruiker opdraagt ​​de toepassing af te sluiten door op de knop Start te drukken. Typische redenen voor een fout hier zijn: * De permanente opslag is niet toegankelijk * Het schema voor de permanente opslag is niet compatibel met het huidige model voor beheerde objecten Controleer de foutmelding om te bepalen wat het werkelijke probleem was. * / NSLog (@ "Niet opgeloste fout% @,% @", fout, [fout userInfo]); abort ();  return persistentStoreCoordinator;  

De toegevoegde code was de optie NSDictionary die Core Data zal vertellen om automatische migraties uit te voeren.

We zijn bijna klaar. De volgende stap is het wijzigen van de klassebestanden voor de gebeurtenisentiteit om de nieuwe naam weer te geven. Om dit te doen gebruiken we mijn favoriete functie van Xcode, de Refactor-functie. Zoals geïmpliceerd door de naam, zal deze functie refactoren en een meer geavanceerde Find & Replace uitvoeren op uw project voor situaties zoals deze.

Om dit te doen, moet je Event.m openen en de tekst 'Event' in dat bestand selecteren. Ga dan naar: Bewerken> Refactor (Cmd + Shift + J). Omhoog komt een venster met opties en velden zoals de onderstaande schermafbeelding. Typ het woord 'Ronde' in het veld 'Gebeurtenis in'. Klik op Voorbeeld en u krijgt de uitvoer van alle wijzigingen:

Als u wilt onderzoeken wat dit gaat doen, klik dan op een van de bestanden in het resultatenvenster en het toont u details over wat het zal veranderen. Het zal ook de Event.h- en Event.m-bestanden voor ons hernoemen. Merk op dat vorige xcdatamodel-bestanden met de specifieke NSManagedObject-klasse die wordt vervangen, een kleine wijziging zullen ondergaan. Het verandert de klassenaam van de entiteit, niet de entiteitsnaam, dus als een apparaat door migratie moet gaan, kan het nog steeds de entiteiten NSManagedObject-klasse en gerelateerde methoden gebruiken.

Klik op toepassen. Dat is het. Als veiligheidsmaatregel zal het ook een momentopname maken, nog zo'n geweldige functie van XCode. Dus als het allemaal fout gaat, kun je gewoon teruggaan naar de vorige momentopname, net als Time Machine maar zonder alle sterren en swirly galaxy UI.

Helaas worden niet alle benodigde wijzigingen opgevangen. Er zijn nog steeds enkele delen van de LapTimer-toepassing die verwijzen naar Gebeurtenis. Dus een snelle Find & Replace is in orde. Ga naar: Bewerken> Zoeken in project. In het nieuwe venster voer je Event in als find en Lap als de replace. Verwijder het vinkje bij 'Negeer Case' omdat we alleen het strenge hoofdlettergebruik van de vondst willen ophalen. Wijzig vervolgens de vervolgkeuzelijst waarin 'Bevat' is geselecteerd en selecteer 'Gehele woorden'. Dit zal de vondst beperken tot precies wat we nodig hebben.

Klik op zoeken. Bekijk de wijzigingen. Als alles goed is gegaan, voer dan de vervanging uit!

Het actieve schema wijzigen

We hebben dus een nieuwe versie van het schema gemaakt, enkele wijzigingen aangebracht en nu is het tijd om de toepassing in het nieuwe schema te plaatsen.

Niets vervelends hier. Selecteer het nieuwe schema dat u als actief wilt instellen en navigeer naar: Ontwerp> Gegevensmodel> Huidige versie instellen. Het groene vinkje gaat naar het nieuwe schema en het is allemaal klaar voor gebruik.

Bouw en voer de applicatie uit. Alles zou goed moeten zijn en de applicatie zou moeten worden geopend, gemigreerd en uitgevoerd. U zult deze migratie helemaal niet opmerken, zelfs geen debuggeroutput. Maar het feit dat de code draait en werkt, bewijst dat deze is gemigreerd.

Samenvatting

Dus de applicatie heeft nu een gewijzigde entiteitsnaam. Dit kan van tijd tot tijd gebeuren bij de ontwikkeling van een toepassing. U kunt met ditzelfde proces nieuwe eigenschappen toevoegen met deze lichtgewicht migratiemethode.

Als u het type van een eigenschap moet wijzigen of geavanceerdere wijzigingen moet doorvoeren, moet u de migratie van het modelmodelobject bekijken. Dit is een meer geavanceerde methode van wat we hebben uitgevoerd, waarvoor extra configuraties en code nodig zijn. De documentatie van Apple iOS heeft een goed verloop van dit geavanceerde migratieproces.