Persisterende gegevens over het starten van applicaties is een vereiste die de meeste iOS-applicaties hebben, van het opslaan van gebruikersvoorkeuren met behulp van het systeem met gebruikersstandaarden tot het beheren van grote datasets in een relationele database. In dit artikel verkennen we de meest gebruikte strategieën voor het opslaan van gegevens in een iOS-toepassing. Ik zal het ook hebben over het bestandssysteem op iOS en hoe applicatie-sandboxing de persistentie van gegevens beïnvloedt.
Je hebt een lange weg afgelegd, sprinkhaan, en je hebt veel geleerd. Er is echter één essentieel aspect van de ontwikkeling van iOS dat we nog niet hebben besproken, namelijk datapersentie. Vrijwel elke iOS-applicatie slaat gegevens op voor later gebruik. De gegevens die uw iOS-applicatie opslaat, kunnen van alles zijn, van gebruikersvoorkeuren tot tijdelijke caches of zelfs grote relationele gegevenssets.
Voordat ik de meest gangbare data-persistentiestrategieën die ontwikkelaars op het iOS-platform bespreken, bespreekt, zal ik eerst enkele minuten gaan discussiëren over het bestandssysteem en het concept van sandboxing van applicaties. Dacht je echt dat je de gegevens van je applicatie kon opslaan waar je maar wilt in het bestandssysteem? Denk nog eens na, padawan.
Beveiliging op het iOS-platform was een van de topprioriteiten van Apple sinds de iPhone in 2007 werd geïntroduceerd. In tegenstelling tot OS X-applicaties wordt een iOS-applicatie in een toepassingssandbox geplaatst. In tegenstelling tot wat de meeste mensen denken, verwijst de sandbox van een toepassing niet alleen naar de sandbox-map van een toepassing in het bestandssysteem. De toepassingssandbox bevat ook gecontroleerde en beperkte toegang tot gebruikersgegevens die zijn opgeslagen op het apparaat, systeemservices en hardware.
Met de introductie van de Mac App Store is Apple ook begonnen met het afdwingen van sandboxes van applicaties op OS X. Hoewel de beperkingen van OS X-toepassingen niet zo strikt zijn als die voor iOS-toepassingen, is het algemene concept vergelijkbaar maar niet identiek. De toepassingssandbox van een iOS-toepassing bevat bijvoorbeeld de toepassingsbundel, wat niet geldt voor OS X-toepassingen. De redenen voor deze verschillen zijn voornamelijk historisch.
Het besturingssysteem installeert elke iOS-toepassing in een sandbox-map, die de map met toepassingsbundels en drie extra mappen bevat, documenten, Bibliotheek, en tmp. De sandbox-map van de toepassing, die vaak wordt aangeduid als de huis map, toegankelijk door een eenvoudige Foundation-functie aan te roepen, NSHomeDirectory ()
.
NSLog (@ "HOME>% @", NSHomeDirectory ());
Je kunt dit zelf proberen. Maak een nieuw Xcode-project op basis van de Toepassing enkele weergave sjabloon en noem het Data Persistence.
Open TSPAppDelegate.m en voeg het bovenstaande codefragment toe aan toepassing: didFinishLaunchingWithOptions:
.
Als u de toepassing uitvoert in de iOS Simulator, ziet de uitvoer in de console er ongeveer zo uit als de onderstaande uitvoer.
2014-03-27 09: 48: 16.794 Data Persistence [1426: 60b] START> / Gebruikers / Bart / Bibliotheek / Application Support / iPhone Simulator / 7.1 / Toepassingen / 5024403A-C65E-44DD-BCD2-F93097FB502E
Als u de toepassing echter op een fysiek apparaat uitvoert, ziet de uitvoer er een beetje anders uit zoals u hieronder kunt zien. De toepassingssandbox en de opgelegde beperkingen zijn echter identiek.
2014-03-27 09: 48: 51.571 Data Persistence [1426: 60b] HOME> / var / mobile / Applicaties / A4D17A73-84D7-4628-9E32-AEFEA5EE6153
Het pad naar de toepassingen ophalen documenten map vereist wat meer werk zoals u kunt zien in het onderstaande codefragment.
NSArray * directories = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); NSString * documents = [mappen firstObject]; NSLog (@ "DOCUMENTS>% @", documenten);
Wij gebruiken de NSSearchPathForDirectoriesInDomains ()
functie en geef de NSDocumentDirectory
constant als het eerste argument om aan te geven dat we alleen geïnteresseerd zijn in de applicaties documenten directory. Het tweede en derde argument zijn van minder belang voor deze discussie. De functie retourneert een exemplaar van NSArray
met één resultaat, het pad naar de applicaties documenten directory.
Je vraagt je misschien af waarom ik het gebruik firstObject
in plaats van objectAtIndex:
om het eerste en enige object in de reeks paden op te halen. Hoewel ik er vrij zeker van kan zijn dat de geretourneerde array niet leeg is, als de array leeg zou zijn en de array een bericht zou ontvangen van objectAtIndex:
met een argument van 0
, de toepassing zou crashen vanwege een niet-afgevangen uitzondering.
Door te bellen firstObject
in de array wordt de array echter geretourneerd nul
als het geen objecten bevat, wat betekent dat er geen uitzondering zou worden gegenereerd. Vergeet niet dat de documentatie je vriend is.
Wat is het voordeel van sandboxing? De belangrijkste reden voor sandbox-toepassingen is beveiliging. Door applicaties te beperken tot hun eigen sandbox, kunnen aangetaste applicaties geen schade aan het besturingssysteem of andere applicaties veroorzaken.
Door aangetast toepassingen, ik bedoel zowel applicaties die gehackt zijn, applicaties die opzettelijk kwaadaardig zijn, als applicaties die essentiële bugs bevatten die onbedoeld schade kunnen veroorzaken.
Hoewel applicaties op het iOS-platform sandboxed zijn, kunnen iOS-applicaties via een aantal systeeminterfaces toegang vragen tot bepaalde bestanden of items die zich buiten hun toepassingssandbox bevinden..
Een voorbeeld hiervan is de muziekbibliotheek die op een iOS-apparaat is opgeslagen. Weet echter dat de systeemkaders bij dergelijke gelegenheden verantwoordelijk zijn voor alle bestandsgerelateerde bewerkingen.
Hoewel je vrijwel alles kunt doen wat je wilt in de sandbox van je applicatie, heeft Apple een paar richtlijnen gegeven met betrekking tot wat waar moet worden bewaard. Het is belangrijk om deze richtlijnen om verschillende redenen te kennen. Wanneer een back-up van een iOS-apparaat wordt gemaakt door iTunes, worden niet alle bestanden in de sandbox van een toepassing opgenomen in de back-up.
De tmp map, bijvoorbeeld, zou alleen moeten worden gebruikt voor het tijdelijk opslaan van bestanden. Het besturingssysteem is vrij om deze map te allen tijde te legen, bijvoorbeeld wanneer het apparaat weinig schijfruimte heeft. De tmp map is niet opgenomen in back-ups.
De documenten map is bedoeld voor gebruikersgegevens, terwijl de Bibliotheek map wordt gebruikt voor toepassingsgegevens die niet strikt aan de gebruiker zijn gekoppeld. De caches map in de Bibliotheek map is een andere map waarvan geen back-up wordt gemaakt door iTunes.
Houd er ook rekening mee dat het niet de bedoeling is dat uw toepassing de inhoud van de map met toepassingsbundels wijzigt. De map met toepassingsbundels wordt ondertekend wanneer de toepassing is geïnstalleerd. Door de inhoud van de map met toepassingsbundels op enigerlei wijze te wijzigen, wordt de bovengenoemde handtekening gewijzigd, wat betekent dat het besturingssysteem de toepassing niet opnieuw kan starten. Dit is nog een beveiligingsmaatregel die door Apple is ingevoerd om consumenten te beschermen.
Er zijn verschillende strategieën om toepassingsgegevens op schijf op te slaan. In dit artikel bekijken we een korte vier gemeenschappelijke benaderingen op iOS:
De opties beschreven in dit artikel mogen niet als onderling uitwisselbaar worden beschouwd. Elke strategie heeft zijn voordelen en de nadelen ervan. Laten we beginnen met een kijkje te nemen naar het systeem met gebruikersstandaarden.
Het standaard systeem van de gebruiker is iets dat iOS heeft geërfd van OS X. Hoewel het is gemaakt en ontworpen voor het opslaan van gebruikersvoorkeuren, kan het worden gebruikt voor het opslaan van elk type gegevens zolang het een soort eigenschappenlijst is, NSString
, NSNumber
, NSDate
, NSArray
, NSDictionary
, en NSData
, of een van hun veranderlijke varianten.
De standaard gebruikersdatabase is niets meer dan een verzameling eigenschappenlijsten, één eigenschappenlijst per toepassing. De eigenschappenlijst wordt opgeslagen in een map met de naam voorkeuren in de applicaties Bibliotheek map, die verwijst naar het doel en de functie van de eigenschappenlijst.
Een van de redenen waarom ontwikkelaars van het standaardsysteem van de gebruiker houden, is omdat het zo gemakkelijk te gebruiken is. Bekijk het onderstaande codefragment om te zien wat ik bedoel.
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool: YES forKey: @ "Key1"]; [userDefaults setInteger: 123 forKey: @ "Key2"]; [userDefaults setObject: @ "Some Object" forKey: @ "Key3"]; [userDefaults boolForKey: @ "Key1"]; [userDefaults integerForKey: @ "Key2"]; [userDefaults objectForKey: @ "Key3"]; [userDefaults synchronize];
Door de standardUserDefaults
klassemethode aan NSUserDefaults
, een verwijzing naar het object Shared defaults wordt geretourneerd.
In de laatste regel bellen we synchroniseren
op het object shared defaults om wijzigingen op schijf te schrijven. Het is zelden nodig om aan te roepen synchroniseren
, omdat de standaardinstelling van de gebruiker wijzigingen opslaat wanneer dat nodig is. Als u een instelling opslaat of bijwerkt met behulp van het systeem met gebruikersstandaarden, kan het soms handig of noodzakelijk zijn om de wijzigingen expliciet op schijf op te slaan..
Op het eerste gezicht lijkt het standaardsysteem van de gebruiker niets meer te zijn dan een sleutelwaardewinkel op een specifieke locatie. echter, de NSUserDefaults
klasse, gedefinieerd in het kader van de Foundation, is meer dan een interface voor het beheer van een sleutelwaardewinkel. Bekijk de klasseverwijzing voor meer informatie.
Voordat we verdergaan, plakt u het bovenstaande codefragment in de gedelegeerden van de toepassing toepassing: didFinishLaunchingWithOptions:
methode en voer de applicatie uit in de iOS Simulator. Open een nieuw Finder-venster en navigeer naar Bibliotheek> Toepassingsondersteuning> iPhone-simulator> 7.1> Toepassingen (vervangen "7.1" met de nieuwste versie van iOS).
Zoek de toepassingsmap die overeenkomt met de toepassing door de verschillende, cryptisch genoemde mappen in de toepassingen map. De cryptisch genoemde map is eigenlijk de sandbox-map van de toepassing. Open de sandbox-map van de toepassing voorkeuren map, gelegen in de Bibliotheek map en controleer de inhoud ervan.
U zou een eigenschappenlijst moeten zien met een naam die identiek is aan de bundelidentificatie van de toepassing. Dit is de standaard gebruikers store voor uw applicatie.
Als je het gemakkelijker wilt maken om toegang te krijgen tot de sandbox van een applicatie in de iOS Simulator, raad ik je ten sterkste aan om eens naar SimPholders te kijken. Het is een gratis hulpprogramma dat het werken met de iOS-simulator veel eenvoudiger maakt.
We hebben al eigendommenlijsten in deze serie behandeld. In feite is de back-upopslag van de database met gebruikersstandaarden een eigenschappenlijst. Het gebruik van eigenschappenlijsten is een handige strategie om een objectgrafiek op te slaan en op te halen. Eigenschappenlijsten bestaan al eeuwen, zijn gemakkelijk in gebruik en ze zijn daarom een prima optie om gegevens op te slaan in een iOS-applicatie.
Zoals ik eerder al zei, is het belangrijk om in gedachten te houden dat een eigenschappenlijst alleen gegevens uit de eigenschappenlijst kan opslaan. Betekent dit dat het niet mogelijk is om aangepaste modelobjecten op te slaan met behulp van eigenschappenlijsten? Nee, het is mogelijk. Aangepaste modelobjecten moeten echter worden gearchiveerd (een vorm van serialisatie) voordat ze in een eigenschappenlijst kunnen worden opgeslagen. Archiveren van een object betekent eenvoudigweg dat het object moet worden geconverteerd naar een gegevenstype dat kan worden opgeslagen in een eigenschappenlijst, zoals een NSData
aanleg.
Herinner je je de NSCoding
protocol gedefinieerd in het kader van de Stichting? De NSCoding
protocol definieert twee methoden,initWithCoder:
en encodeWithCoder:
, die een klasse moet implementeren om toe te staan dat instanties van de klasse worden gecodeerd en gedecodeerd.
Codering en decodering zijn de onderliggende mechanismen voor archivering en distributie van objecten. Hoe objecten archiveringswerken iets later in deze serie duidelijk zullen worden. In deze les laat ik je alleen zien hoe je arrays en woordenboeken op schijf schrijft met behulp van eigenschappenlijsten.
Het volgende codefragment zou u een idee moeten geven van hoe gemakkelijk het is om een array of woordenboek naar schijf te schrijven. In theorie kan de objectgrafiek die in een eigenschappenlijst is opgeslagen, zo complex of zo groot zijn als u wilt. Houd er echter rekening mee dat eigenschappenlijsten niet bedoeld zijn om tientallen of honderden megabytes aan gegevens op te slaan. Als u probeert ze op die manier te gebruiken, leidt dit waarschijnlijk tot verminderde prestaties.
NSArray * fruits = @ [@ "Apple", @ "Mango", @ "Pineapple", @ "Plum", @ "Apricot"]; NSString * filePathFruits = [documents stringByAppendingPathComponent: @ "fruits.plist"]; [fruits writeToFile: filePathFruits atomically: YES]; NSDictionary * miscDictionary = @ @ "anArray": fruits, @ "aNumber": @ 12345, @ "aBoolean": @YES; NSString * filePathDictionary = [documents stringByAppendingPathComponent: @ "misc-dictionary.plist"]; [miscDictionary writeToFile: filePathDictionary atomically: YES]; NSArray * loadedFruits = [NSArray arrayWithContentsOfFile: filePathFruits]; NSLog (@ "Fruits Array>% @", loadedFruits); NSDictionary * loadedMiscDictionary = [NSDictionary dictionaryWithContentsOfFile: filePathDictionary]; NSLog (@ "Misc Dictionary>% @", loadedMiscDictionary);
Laten we het bovenstaande codefragment bekijken. We beginnen met het opslaan van een verwijzing naar een array letterlijk in een variabele met de naam fruit
. We maken het bestandspad voor het opslaan van de eigenschappenlijst die we gaan maken. Het bestandspad wordt gemaakt door een tekenreeks toe te voegen aan het bestandspad van de documenten directory, die we eerder in deze les hebben opgehaald. De reeks die we toevoegen, is de naam van de eigenschappenlijst, inclusief de extensie, .plist-die we in een seconde creëren.
Het schrijven van de array naar schijf is net zo eenvoudig als bellen writeToFile: atomair:
op de array. U kunt het atomair
vlag voor nu.
Zoals het voorbeeld illustreert, volgt het schrijven van een woordenboek op een schijf een vergelijkbaar patroon. Het voorbeeld illustreert ook hoe u arrays en woordenboeken kunt maken in een eigenschappenlijst, maar dit is iets dat we al eerder in deze serie hebben behandeld.
Start de applicatie in de iOS Simulator en navigeer naar de applicaties documenten directory zoals we eerder zagen. In deze map ziet u de twee eigenschappenlijsten die we zojuist hebben gemaakt.
Als uw toepassing gegevensgestuurd is en met grote hoeveelheden gegevens werkt, wilt u misschien SQLite bekijken. Wat is SQLite? De slogan op de SQLite-website luidt: "Klein, snel, betrouwbaar, kies een drie.", Wat het mooi samenvat.
SQLite is een bibliotheek die een lichtgewicht ingesloten relationele database implementeert. Zoals de naam al aangeeft, is deze gebaseerd op de SQL-standaard (Structured Query Language) net als MySQL en PostgreSQL.
Het belangrijkste verschil met andere SQL-databases is dat SQLite draagbaar is, zeer licht van gewicht, en dat het serverloos is in plaats van een afzonderlijk proces dat toegankelijk is vanuit de clienttoepassing. Met andere woorden, het is ingebed in de applicatie en daarom erg snel.
De SQLite-website beweert dat dit de meest gebruikte SQL-database is. Ik weet niet of dat nog steeds het geval is, maar het is zeker een populaire keuze voor gegevensopslag aan de client. Aperture en iPhoto vertrouwen bijvoorbeeld op SQLite voor een deel van hun gegevensopslag.
Het voordeel dat SQLite heeft om direct met objecten te werken, is dat SQLite sneller ordes van grootte is, wat grotendeels te wijten is aan hoe relationele databases en objectgeoriënteerde programmeertalen fundamenteel verschillen.
Om de kloof tussen SQLite en Objective-C te overbruggen, een aantal Object Relational Mapping (ORM) oplossingen zijn in de loop van de tijd gecreëerd. De ORM die Apple heeft gemaakt voor iOS en OS X is genoemd Kerngegevens, waar we later in deze les naar zullen kijken.
SQLite gebruiken op iOS betekent werken met een op C gebaseerde bibliotheek. Als je de voorkeur geeft aan een objectgerichte oplossing, dan raad ik Gus Mueller's (Flying Meat, Inc.) Objective-C-wrapper voor SQLite, FMDB.
Het maakt het werken met SQLite veel gemakkelijker als u de voorkeur geeft aan een objectgeoriënteerde interface. De bibliotheek ondersteunt ARC (Automatische referentietelling) uit de doos en is zeer performant. Ik heb in het verleden FMDB gebruikt en ben erg blij met de API en de robuustheid en betrouwbaarheid van de bibliotheek.
Ontwikkelaars die nieuw zijn bij Core Data, verwarren vaak Core Data voor een database, terwijl het echt een relationele kaartoplossing voor objecten is, gemaakt en onderhouden door Apple. Matt Gallagher heeft een geweldige post geschreven over de verschillen tussen kerngegevens en een database. Core Data biedt een relationeel objectgericht model dat kan worden geserialiseerd naar een XML-, binary- of SQLite-winkel. Core Data ondersteunt zelfs een in-memory store.
Waarom zou u Core Data gebruiken in plaats van SQLite? Door deze vraag te stellen, ga je er ten onrechte van uit dat Core Data een database is. Het voordeel van het gebruik van basisgegevens is dat u met objecten werkt in plaats van met onbewerkte gegevens, zoals rijen in een SQLite-database of gegevens die zijn opgeslagen in een XML-bestand. Hoewel Core Data enkele moeilijke jaren had toen het voor het eerst werd uitgebracht, is het uitgegroeid tot een robuust framework met veel functies, zoals automatische migraties, veranderingstracking, fouten en geïntegreerde validatie.
Een andere geweldige functie die veel ontwikkelaars op prijs stellen, is de in modelcode ingebouwde editor voor het kerngegevensmodel, waarmee ontwikkelaars hun gegevensmodel via een grafische interface kunnen modelleren.
Of Core Data de juiste oplossing voor uw toepassing is, hangt af van de gegevens die u wilt beheren, zowel wat betreft de hoeveelheid als het onderliggende model. Als u van plan bent om extreem grote gegevensreeksen te beheren, kan Kerngegevens na verloop van tijd een prestatiebottleneck worden. In dat geval kan SQLite een betere oplossing zijn.
U hebt waarschijnlijk gehoord van iCloud en u vraagt zich misschien af waar iCloud in het verhaal van gegevenspersistentie past. iCloud is geen vorm van gegevenspersistentie zoals SQLite of Core Data. In plaats daarvan is het een platform of service om gebruikersgegevens beschikbaar te maken op meerdere apparaten en meerdere exemplaren van een toepassing, of zelfs een familie van toepassingen.
Het iCloud-platform omvat verschillende services of componenten. Het component dat ons interesseert is iCloud-opslag, welke drie soorten opslag omvat:
Als u meer wilt lezen over iCloud-opslag, raad ik u aan een serie over iCloud-opslag te lezen die ik eerder dit jaar schreef.
Je moet nu een goed idee hebben van de opties die je hebt op het gebied van datastandigheid bij het ontwikkelen voor het iOS-platform. Houd in gedachten dat niet alle strategieën die we hebben behandeld gelijk zijn.
Deze serie komt langzaam ten einde. In de volgende twee tranches zullen we een nieuwe applicatie maken om wat we tot nu toe hebben geleerd in de praktijk te brengen. De beste manier om te leren is door te doen.