Data Persistence og Sandboxing på IOS

Vedvarende data på tvers av programlanseringer er et krav at de fleste iOS-applikasjoner har, fra lagring av brukerpreferanser ved å bruke brukerstandardsystemet til å administrere store datasett i en relasjonsdatabase. I denne artikkelen vil vi utforske de vanligste strategiene som brukes til lagring av data i et iOS-program. Jeg vil også snakke om filsystemet på iOS og hvordan applikasjons sandboxing påvirker datasikkerhet.


Introduksjon

Du har kommet langt, gresshopper, og du har lært mye. Imidlertid er det et viktig aspekt av IOS-utvikling som vi ikke har diskutert ennå, data utholdenhet. Nesten alle iOS-applikasjoner lagrer data for senere bruk. Dataene dine iOS-applikasjonsbutikker kan være alt fra brukerpreferanser til midlertidige cacher eller til og med store relasjonsdatasett.

Før du diskuterer de vanligste datasikkerhetsstrategiene som utviklerne har på iOS-plattformen, skal jeg først tilbringe noen minutter å diskutere filsystemet og begrepet søknads sandboxing. Tror du virkelig at du kan lagre programmets data uansett hvor du vil på filsystemet? Tenk igjen, padawan.


Filsystem og applikasjon Sandboxing

Sikkerhet på iOS-plattformen har vært en av Apples topprioriteter helt siden iPhone ble introdusert i 2007. I motsetning til OS X-applikasjoner, er et iOS-program plassert i en applikasjons sandkasse. I motsetning til hva folk flest mener, refererer en applikasjons sandkasse ikke bare til en applikasjons sandkassekatalog i filsystemet. Programsandboksen inneholder også kontrollert og begrenset tilgang til brukerdata lagret på enheten, systemtjenester og maskinvare.

Med introduksjonen av Mac App Store har Apple begynt å håndheve applikasjons sandboxing på OS X også. Selv om begrensningene på OS X-applikasjoner ikke er like strenge som de som er pålagt iOS-applikasjoner, er det generelle konseptet lik, men ikke identisk. Applikasjonssandboken til et iOS-program inneholder for eksempel programbuntet, som ikke er sant for OS X-applikasjoner. Årsakene til disse forskjellene er hovedsakelig historiske.

Sandboxing og kataloger

Operativsystemet installerer hvert iOS-program i en sandkassekatalog, som inneholder applikasjonspakkekatalogen og tre ekstra kataloger, dokumenter, Bibliotek, og tmp. Programmets sandbokkatalog, ofte referert til som sin hjem katalog, kan nås ved å ringe en enkel Foundation-funksjon, NSHomeDirectory ().

NSLog (@ "HOME>% @", NSHomeDirectory ());

Du kan prøve dette selv. Opprett et nytt Xcode-prosjekt basert på Enkeltvisningsprogram mal og navn den Data Persistens.

Åpen TSPAppDelegate.m og legg til koden ovenfor til applikasjons: didFinishLaunchingWithOptions:.

Hvis du kjører programmet i iOS-simulatoren, vil utgangen i konsollen se ut som utgangen vist nedenfor.

2014-03-27 09: 48: 16.794 Data Persistence [1426: 60b] HJEM> / Brukere / Bart / Bibliotek / Programstøtte / iPhone Simulator / 7.1 / Programmer / 5024403A-C65E-44DD-BCD2-F93097FB502E

Men hvis du kjører programmet på en fysisk enhet, ser utgangen litt annerledes ut som du kan se nedenfor. Søknadssandboken og begrensningene er identiske skjønt.

2014-03-27 09: 48: 51.571 Data Persistence [1426: 60b] HOME> / var / mobile / Programmer / A4D17A73-84D7-4628-9E32-AEFEA5EE6153

Henter banen til programmets dokumenter katalogen krever litt mer arbeid som du kan se i kodestykket nedenfor.

NSArray * kataloger = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); NSString * documents = [kataloger firstObject]; NSLog (@ "DOCUMENTS>% @", dokumenter);

Vi bruker NSSearchPathForDirectoriesInDomains () funksjon og passere NSDocumentDirectory konstant som det første argumentet for å indikere at vi bare er interessert i søknadens dokumenter katalogen. Det andre og tredje argumentet har mindre betydning for denne diskusjonen. Funksjonen returnerer en forekomst av NSArray inneholder ett resultat, banen til programmets dokumenter katalog.

Du lurer kanskje på hvorfor jeg bruker firstObject i stedet for objectAtIndex: å hente den første og eneste objektet i en rekke stier. Selv om jeg kan være ganske sikker på at arrayet returnerte ikke er tomt, hvis arrayet skulle være tomt og arrayet ville motta en melding om objectAtIndex: med et argument av 0, søknaden ville krasje på grunn av et uncaught unntak.

Ved å ringe firstObject På matrisen returnerer imidlertid matrisen nil hvis det ikke inneholder noen objekter, noe som betyr at ingen unntak vil bli kastet. Husk at dokumentasjonen er din venn.

Hvorfor Sandboxing?

Hva er fordelen med sandboxing? Den primære grunnen til sandboxing-applikasjoner er sikkerhet. Ved å begrense applikasjoner til egen sandkasse kan kompromitterte applikasjoner ikke forårsake skade på operativsystemet eller andre applikasjoner.

Av kompromittert applikasjoner, mener jeg begge applikasjoner som har blitt hacket, applikasjoner som er forsettlig ondsinnet, samt programmer som inneholder kritiske feil som utilsiktet kan forårsake skade.

Selv om applikasjoner er sandbokserte på iOS-plattformen, kan iOS-programmer be om tilgang til bestemte filer eller eiendeler som ligger utenfor applikasjonssandboken gjennom en rekke systemgrensesnitt.

Et eksempel på dette er musikkbiblioteket lagret på en iOS-enhet. Vet imidlertid at systemrammene har ansvar for filrelaterte operasjoner ved slike anledninger.

Hva går der?

Selv om du kan gjøre stort sett alt du vil ha i søknadens sandkasse, har Apple gitt noen retningslinjer med hensyn til hva som skal lagres der. Det er viktig å vite om disse retningslinjene av flere grunner. Når en IOS-enhet er sikkerhetskopiert av iTunes, er ikke alle filene i en applikasjons sandkasse inkludert i sikkerhetskopien.

De tmp katalog, for eksempel, bør bare brukes til midlertidig lagring av filer. Operativsystemet kan til enhver tid tømme denne katalogen, for eksempel når enheten har lite diskplass. De tmp katalogen er ikke inkludert i sikkerhetskopier.

De dokumenter katalog er ment for brukerdata, mens Bibliotek katalogen brukes til applikasjonsdata som ikke er strengt knyttet til brukeren. De Caches katalog i Bibliotek katalog er en annen katalog som ikke er sikkerhetskopiert av iTunes.

Vær også oppmerksom på at søknaden din ikke skal endre innholdet i programbuntkatalogen. Programbuntkatalogen er signert når applikasjonen er installert. Ved å endre innholdet i programbuntkatalogen på noen måte, endres ovennevnte signatur, noe som betyr at operativsystemet ikke tillater at programmet startes igjen. Dette er et annet sikkerhetsmål som Apple har tatt for å beskytte forbrukerne.


Data Persistence Options

Det er flere strategier for lagring av applikasjonsdata på disk. I denne artikkelen tar vi en kort titt på fire vanlige tilnærminger på IOS:

  • brukerstandarder
  • eiendomslister
  • SQLite
  • Kjernedata

Alternativene beskrevet i denne artikkelen bør ikke betraktes som utbytbare. Hver strategi har sine fordeler, så vel som dens ulemper. La oss starte med å se på standardinnstillingene for brukeren.


Brukerstandarder

Brukerens standardinnstilling er noe som iOS arvet fra OS X. Selv om det ble opprettet og designet for å lagre brukerpreferanser, kan det brukes til lagring av alle typer data så lenge det er en egenskapslistype, NSString, NSNumber, NSDate, NSArray, NSDictionary, og NSData, eller noen av deres mutable varianter.

Brukerens standarddatabase er ikke noe mer enn en samling av eiendomslister, en eiendomsliste per applikasjon. Egenskapslisten er lagret i en navngitt mappe Preferanser i programmets Bibliotek mappe, som hint på eiendomslistens formål og funksjon.

En av grunnene til at utviklere som brukerens standardinnstillinger er fordi det er så enkelt å bruke. Se koden nedenfor for å se hva jeg mener.

NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool: YES forKey: @ "Key1"]; [userDefaults setInteger: 123 forKey: @ "Key2"]; [userDefaults setObject: @ "Some Object" for Key: @ "Key3"]; [userDefaults boolForKey: @ "Key1"]; [userDefaults integerForKey: @ "Key2"]; [userDefaults objectForKey: @ "Key3"]; [userDefaults synkronisere];

Ved å ringe standardUserDefaults klassemetode på NSUserDefaults, en referanse til objektet for felles standard returneres.

I den siste linjen kaller vi synkron på de delte standardinnstillingene objekt for å skrive noen endringer på disken. Det er sjelden nødvendig å påberope seg synkron, fordi brukerens standardinnstillinger lagrer endringer når det er nødvendig. Men hvis du lagrer eller oppdaterer en innstilling ved hjelp av standardinnstillingene for systemet, kan det noen ganger være nyttig eller nødvendig å eksplisitt lagre endringene på disken.

Ved første øyekast synes brukerens standard system å være noe mer enn en nøkkelverdibutikk som ligger på et bestemt sted. Imidlertid NSUserDefaults klassen, definert i stiftelsesrammen, er mer enn et grensesnitt for å administrere en nøkkelverdibutikk. Ta en titt på klassens referanse for mer informasjon.

Før vi går videre, lim inn koden ovenfor i programdelegatet applikasjons: didFinishLaunchingWithOptions: metode og kjør programmet i iOS-simulatoren. Åpne et nytt Finder-vindu og naviger til Bibliotek> Programstøtte> iPhone Simulator> 7.1> Programmer (erstatte "7.1" med den nyeste versjonen av iOS).

Finn søkemappen som tilsvarer søknaden ved å inspisere de forskjellige mappene som er kryptisk navngitte i applikasjoner mappe. Den kryptisk navngitte mappen er faktisk applikasjons sandbokkatalogen. I applikasjons sandbokkatalogen, åpne Preferanser mappe, plassert i Bibliotek mappe og inspisere innholdet.

Du bør se en eiendomsliste med et navn som er identisk med programmets buntidentifikator. Dette er brukerstandardbutikken for din søknad.

Hvis du vil gjøre det enklere å få tilgang til sandboken til et program i iOS-simulatoren, anbefaler jeg sterkt at du tar en titt på SimPholders. Det er et gratis verktøy som gjør det enklere å jobbe med iOS Simulator.


Eiendomslister

Vi har allerede dekket eiendomslister i denne serien. Faktisk er backing-butikken til brukerens standarddatabase en eiendomsliste. Bruke eiendomslister er en praktisk strategi for å lagre og hente en objektgraf. Eiendomslister har eksistert i årevis, er enkle å bruke, og de er derfor et godt alternativ for lagring av data i et iOS-program.

Som nevnt tidligere, er det viktig å huske på at en eiendomsliste kun kan lagre eiendomsliste data. Betyr dette at det ikke er mulig å lagre egendefinerte modellobjekter ved hjelp av eiendomslister? Nei, det er mulig. Imidlertid må egendefinerte modellobjekter arkiveres - en form for serialisering - før de kan lagres i en eiendomsliste. Arkivering av et objekt betyr ganske enkelt at objektet må konverteres til en datatype som kan lagres i en eiendomsliste, for eksempel en NSData forekomst.

Arkivere objekter

Husker du NSCoding protokollen definert i stiftelsens rammeverk? De NSCoding protokollen definerer to metoder,initWithCoder: og encodeWithCoder:, som en klasse må implementere for å tillate forekomster av klassen å bli kodet og dekodet.

Koding og dekoding er de underliggende mekanismene for objektarkiv og distribusjon. Hvordan objektarkivarbeid blir klar senere i denne serien. I denne leksjonen viser jeg deg bare hvordan du skriver arrays og ordbøker til disk ved hjelp av eiendomslister.

Skriver til fil

Følgende kodestykke skal gi deg en ide om hvor enkelt det er å skrive en matrise eller en ordbok på disken. I teorien kan objektgrafen som er lagret i en eiendomsliste være så kompleks eller så stor som du vil. Vær imidlertid oppmerksom på at eiendomslister ikke er ment å lagre titalls eller hundrevis av megabyte data, og forsøk på å bruke dem på den måten vil trolig føre til forringet ytelse.

NSArray * fruits = @ [@ "Apple", @ "Mango", @ "Pineapple", @ "Plum", @ "Apricot"]; NSString * filePathFruits = [documents stringByAppendingPathComponent: @ "fruits.plist"]; [frukt writeToFile: filePathFruits atomisk: JA]; NSDictionary * miscDictionary = @ @ "anArray": frukt, @ "aNumber": @ 12345, @ "aBoolean": @YES; NSString * filePathDictionary = [documents stringByAppendingPathComponent: @ "misc-dictionary.plist"]; [miscDictionary writeToFile: filePathDictionary atomisk: JA]; NSArray * loadedFruits = [NSArray arrayWithContentsOfFile: filePathFruits]; NSLog (@ "Fruits Array>% @", loadedFruits); NSDictionary * loadedMiscDictionary = [NSDictionary DictionaryWithContentsOfFile: filePathDictionary]; NSLog (@ "Diverse ordbok>% @", loadedMiscDictionary);

La oss se på koden ovenfor. Vi begynner med å lagre en referanse til en matrise i en variabel som heter frukt. Vi lager filbanen for å lagre eiendomslisten som vi skal lage. Filbanen er opprettet ved å legge til en streng til filbanen til dokumenter katalog, som vi hentet tidligere i denne leksjonen. Strengen som vi legger til, vil være navnet på eiendomslisten - inkludert utvidelsen, .plist-som vi vil lage om et sekund.

Å skrive arrayen til disk er så enkelt som å ringe writeToFile: atomically: på matrisen. Du kan ignorere atomically flagg for nå.

Som eksemplet illustrerer, følger en ordbok på disk etter et lignende mønster. Eksemplet illustrerer også hvordan man lager arrays og ordbøker fra en eiendomsliste, men dette er noe vi allerede dekket tidligere i denne serien.

Kjør programmet i iOS-simulatoren og naviger til programmets dokumenter katalog som vi så tidligere. I denne katalogen bør du se de to eiendomslister vi nettopp har opprettet.


SQLite

Hvis søknaden din er datastyrt og fungerer med store mengder data, vil du kanskje se på SQLite. Hva er SQLite? Tagline på SQLite nettsiden leser "Small. Fast. Pålitelig. Velg noen tre.", Som summerer det pent.

SQLite er et bibliotek som implementerer en lett integrert relasjonsdatabase. Som navnet antyder, er det basert på SQL-standarden (Strukturert spørrespråk) akkurat som MySQL og PostgreSQL.

Hovedforskjellen med andre SQL-databaser er at SQLite er bærbar, veldig lett, og at den er serverløs i stedet for en egen prosess som er tilgjengelig fra klientprogrammet. Med andre ord, det er innebygd i søknaden og derfor veldig fort.

SQLite-nettstedet hevder at det er den mest distribuerte SQL-databasen. Jeg vet ikke om det fortsatt er tilfelle, men det er absolutt et populært valg for data lagring på klientsiden. Blenderåpning og iPhoto, for eksempel, stole på SQLite for noen av deres datalagring.

Fordelen SQLite har over å jobbe direkte med objekter er at SQLite er størrelsesordre raskere, noe som i stor grad skyldes hvordan relasjonsdatabaser og objektorienterte programmeringsspråk fundamentalt er forskjellige.

For å bygge bro over gapet mellom SQLite og Objective-C, et antall Objektrelasjonell kartlegging (ORM) løsninger er opprettet over tid. ORM som Apple har opprettet for iOS og OS X er oppkalt Kjernedata, som vi vil se nærmere på i denne leksjonen.

Flying Meats FMDB

Å bruke SQLite på iOS betyr å jobbe med et C-basert bibliotek. Hvis du foretrekker en objektorientert løsning, anbefaler jeg Gus Muellers (Flying Meat, Inc.) Objective-C wrapper for SQLite, FMDB.

Det gjør det lettere å jobbe med SQLite hvis du foretrekker et objektorientert grensesnitt. Biblioteket støtter ARC (Automatisk referansetelling) ut av esken og er veldig opptatt. Jeg har brukt FMDB tidligere og har vært veldig fornøyd med API og bibliotekets robusthet og pålitelighet.


Kjernedata

Utviklere som er ny i Core Data, feiler ofte Core Data for en database, mens det egentlig er en objektrelasjonell kartløsningsløsning opprettet og vedlikeholdt av Apple. Matt Gallagher har skrevet et stort innlegg om forskjellene mellom Core Data og en database. Core Data gir en relasjonsobjektorientert modell som kan serieiseres i en XML-, binær- eller SQLite-butikk. Kjernedata støtter selv en minnesbutikk.

Hvorfor skal du bruke Core Data i stedet for SQLite? Ved å stille dette spørsmålet tar du feilaktig ut at Core Data er en database. Fordelen med å bruke Core Data er at du jobber med objekter i stedet for rå data, for eksempel rader i en SQLite-database eller data lagret i en XML-fil. Selv om Core Data hadde noen vanskelige år da den først ble utgitt, har den vokst til et robust rammeverk med mange funksjoner, for eksempel automatiske migreringer, endringssporing, feil og integrert validering.

En annen flott funksjon som mange utviklere setter pris på, er Core Data-modelleditoren bygget inn i Xcode som lar utviklere modellere datamodellen gjennom et grafisk grensesnitt.

Hvorvidt Core Data er den riktige løsningen for søknaden din, avhenger av dataene du planlegger å administrere, både når det gjelder mengde så vel som den underliggende modellen. Hvis du planlegger å administrere ekstremt store datasett, kan Core Data bli en ytelse flaskehals over tid. I så fall kan SQLite være en bedre løsning.


iCloud

Du har sikkert hørt om iCloud, og du lurer kanskje på hvor iCloud passer inn i historien om data utholdenhet. iCloud er ikke en form for data utholdenhet som SQLite eller Core Data er. I stedet er det en plattform eller tjeneste for å gjøre brukerdata tilgjengelig over flere enheter og flere forekomster av et program - eller til og med en familie av applikasjoner.

ICloud-plattformen omfatter flere tjenester eller komponenter. Komponenten som interesserer oss er iCloud Storage, som inkluderer tre typer lagringsplass:

  • nøkkelverdi lagring
  • dokument lagring
  • Kjerne datalagring.

Hvis du vil lese mer om iCloud Storage, anbefaler jeg at du leser en serie om iCloud Storage som jeg skrev tidligere i år.

Konklusjon

Du bør nå ha en god ide om alternativene du har når det gjelder data utholdenhet når du utvikler for iOS-plattformen. Husk at ikke alle strategiene vi har dekket er like.

Denne serien kommer sakte til sakte. I de neste to delene vil vi opprette et nytt program for å sette det vi har lært så langt inn i praksis. Den beste måten å lære på er å gjøre.