Lokalne przechowywanie danych na iOS – kiedy i jak je wykorzystywać? Keychain, Core Data i inne opcje

Lokalne przechowywanie danych na iOS – kiedy i jak je wykorzystywać? Keychain, Core Data i inne opcje

Korzystanie z aplikacji mobilnych kojarzymy z ciągłym dostępem do internetu i wymianą danych z serwerami. Czasami jednak trzeba pewne informacje zapisać lokalnie.

Przykładowo wtedy, gdy chcemy umożliwić działanie aplikacji w trybie offline, kiedy urządzenie ma zapamiętywać dane logowania albo gdy skracamy czas ładowania dzięki buforowaniu danych.

Istnieje kilka sposobów zapisywania danych w aplikacji. Od prostych UserDefaults po bardziej bezpieczne Keychain lub znacznie potężniejsze jak Core Data. Wykorzystanie każdego z nich zależy od typu i rozmiaru zapisywanych danych, dlatego warto o tym pomyśleć już na początku projektu. Niezależnie od tego, gdzie je umieścimy, zawsze trzeba upewnić się, że są one bezpiecznie przechowywane.

W tym artykule przedstawię niektóre dostępne rozwiązania, wskażę różnice między nimi, a także sposoby ich wykorzystania.

Popularne metody implementacji pamięci lokalnej na iOS

Pamięć lokalna służy do przechowywania danych aplikacji internetowych na urządzeniu przy użyciu określonych platform, narzędzi i metod charakterystycznych dla różnych systemów. W przypadku iOS wybór danej metody zależy od tego, jakie dane chcesz przechowywać i w jakiej ilości.

Najczęściej stosowane metody implementacji pamięci lokalnej w systemie iOS to:

  • Property list in Swift
  • File System
  • UserDefaults
  • Keychain
  • Core Data

Co musisz o nich wiedzieć?

Property list in Swift

Plik listy właściwości, lepiej znany jako plist , to szczególny rodzaj pliku, w którym można przechowywać dane w parach klucz-wartość. W rzeczywistości jest to plik XML. W aplikacjach macOS i iOS najczęstszym przykładem użycia plist jest Info.plist. Przechowuje on wartości ustawień i konfiguracji oraz informacje dotyczące aplikacji. Na żądanie można też dodać więcej wpisów. Najłatwiej go porównać ze słownikiem w Swift. Pliki z listami właściwości mogą być idealne do przechowywania niewielkich ilości danych.W plikach plist można przechowywać takie obiekty, jak:

  • Strings
  • Numbers (Int, Floats)
  • Bools
  • Dates (ISO 8601 formatowany string)
  • Data (NSData, w Objective-C)
  • Arrays
  • Dictionaries.

Po otwarciu pliku plist w edytorze tekstu dane nie wyglądają przejrzyście. To dlatego, że są zorganizowane w formacie łatwym do odczytania przez komputery:

Plik możemy również otworzyć w formie edytora graficznego, który pokazuje dane w znacznie przystępniejszy sposób.

Informacje przechowywane w pliku Info.plist aplikacji można też odczytać za pomocą Bundle:

Pliki plist z łatwością odczytują i komputery, i ludzie. Mogą one służyć do określania wartości środowiskowych aplikacji lub ustawień użytkownika.

File system

System plików obsługuje trwałe przechowywanie plików danych, aplikacji i plików związanych z systemem operacyjnym. Dlatego file system jest jednym z podstawowych zasobów wykorzystywanych przez wszystkie procesory. W systemie iOS działa on na tej samej zasadzie jak na komputerach, czyli używa ścieżek i adresów URL do identyfikacji zasobów na dysku.

My skupimy się na kilku preferowanych folderach:

  1. Documents – to idealne miejsce do zapisywania treści tworzonych przez użytkowników.
  2. tmp – w tym folderze zapiszemy pliki, których aplikacja potrzebuje tylko tymczasowo. System operacyjny może je usunąć, gdy aplikacja nie będzie uruchomiona.
  3. Documents/Inbox – możemy użyć tego katalogu, aby uzyskać dostęp do plików, o których otwarcie aplikacja poprosiła przez podmioty zewnętrzne, takie jak np. załączniki poczty.
  4. Library – jest to katalog najwyższego poziomu dla wszystkich plików, które nie są danymi użytkownika. Możemy tutaj przechowywać np. plik binarny, który dostarcza dane do aplikacji.
  5. Library\Caches – podfolder folderu Library dla wszelkich plików buforowania. Możemy w nim zapisywać pliki, które wkrótce będą potrzebne, czyli np. zdjęcia produktów.

Praca z plikami w aplikacjach iOS jest bardzo łatwa. Każda z nich ma katalog Sandbox, zwany katalogiem Dokumentów i może w nim przechowywać pliki. Do tych czynności wykorzystujemy FileManagera. To wygodny interfejs do zawartości systemu plików i podstawowy sposób interakcji z nimi.

System plików okazuje się przydatny w niektórych przypadkach. W ten sposób można przechowywać na dysku duże obiekty (np. zdjęcia produktów), o ile na urządzeniu jest wystarczająca ilość pamięci lokalnej, translacje, kody błędów lub inne wymagane dane. Interfejs FileManager jest bezpiecznym rozwiązaniem dla wątków. Niestety samo tworzenie ścieżek URL może być podatne na błędy.

UserDefaults

Jest to interfejs do domyślnej bazy danych użytkownika, który służy do przechowywania małych fragmentów danych. Pary klucz-wartość są w niej stale przechowywane podczas uruchamiania aplikacji. Kluczem jest zawsze ciąg znaków, a wartością jeden z typów: dane (data), ciąg znaków (string), liczba (number), data (date), tablica (array) lub słownik (dictionary).

UserDefaults to podklasa NSObject, która daje nam synchroniczne odczyty i zapisy (na poziomie pamięci podręcznej) oraz asynchroniczny poziom trwałości. Dzięki temu nawet jeżeli aplikacja zostanie zamknięta lub urządzenie uruchomi się ponownie, dane pozostaną dostępne.

UserDefaults zapisuje swoje dane w lokalnym pliku plist na dysku. Są one też zachowywane dla kopii zapasowych i przywracania. Obecnie jedynie platforma tvOS posiada limit wynoszący 1MB. Praca z UserDefaults w aplikacji iOS jest bardzo łatwa. Dotyczy to zarówno operacji zapisywania, jak i odczytu danych.

UserDefaults doskonale sprawdza się w przypadku ustawień użytkownika lub niewielkich ilości JSON. To doskonałe narzędzie do przechowywania podstawowych typów danych, ponieważ jest proste w użyciu i nie wymaga innych bibliotek ani frameworków. Jest również bezpieczne dla wątków (pozwala odczytywać i zapisywać dane z dowolnego wątku). Nie jest to jednak rozwiązanie bez wad. UserDefaults nie jest szyfrowane i na dodatek jest podatne na błędne nadpisanie, ponieważ opiera się na dodawanych przez programistę kluczach.

Keychain

Usługa Keychain firmy Apple to mechanizm służący do bezpiecznego i chronionego przechowywania sekretnych danych, takich jak hasła, klucze kryptograficzne czy tokeny użytkownika. Jest zaimplementowany jako baza danych SQLite, do której można uzyskać dostęp tylko za pośrednictwem interfejsów API Keychain.

W systemie macOS każda aplikacja użytkownika może utworzyć dowolną liczbę pęków kluczy. Struktura pęku kluczy w systemie iOS jest inna. Dla wszystkich aplikacji dostępny jest tylko jeden pęk kluczy.

Do obsługi Keychain warto zastanowić się nad użyciem gotowej biblioteki. W moim przypadku będzie to KeychainAccess. Zapisanie elementu przy pomocy wyżej wymienionej biblioteki jest łatwe. Wystarczy utworzyć obiekt Keychain, a następnie przypisać daną wartość pod odpowiedni klucz: 

Odczyt danej wartości jest jeszcze prostszy, ponieważ po utworzeniu obiektu Keychain musimy odwołać się jedynie do elementu znajdującego się pod wskazanym kluczem:

Keychain sprawdza się doskonale jako wyspecjalizowana baza danych do przechowywania metadanych i poufnych informacji. Niestety bezpośrednia interakcja z Keychain jest skomplikowana, zwłaszcza w Swift. Musimy użyć struktury bezpieczeństwa (Security framework), która jest napisana głównie w C, co zmusza nas często do wykorzystywania zewnętrznych bibliotek, ułatwiających pracę z Keychain.

Core Data

Core Data to framework do zarządzania warstwą modelu w Twojej aplikacji iOS. Ta platforma służy do zapisywania, śledzenia, modyfikowania i filtrowania danych. Opiera się głównie na tworzeniu encji Core Data, a także relacji między nimi. Core Data używa SQLite jako trwałego magazynu, ale sam framework nie jest bazą danych. Zapewnia on ogólne i zautomatyzowane rozwiązania typowych zadań związanych z cyklami życia obiektów i zarządzaniem grafami obiektów, w tym trwałością. Core Data domyślnie nie szyfruje swoich danych.

Korzystanie z Core Data jest znacznie bardziej skomplikowane od wcześniej wspomnianych metod i można o tym napisać osobny poradnik. Dlatego tutaj przytoczę jedynie wady i zalety tego rozwiązania.

Core Data nadaje się świetnie do dużych zadań, gdzie musimy śledzić model obiektowy z wieloma jednostkami i relacjami. Posiada mechanizm cofania/ponawiania, automatycznie obsługuje lekkie migracje, a dodatkowo jest bardzo wydajna i zoptymalizowana.

Do minusów zaliczyć można zaawansowaną politykę wątkową, brak wbudowanego szyfrowania czy wyższy próg wejścia od pozostałych sposobów przechowywania danych.

Znasz już podstawowe metody przechowania danych lokalnie. Teraz czas się dowiedzieć, jak wybrać ten najlepszy w danym przypadku.

Keychain vs UserDefaults

Podstawowym elementem różniącym oba te sposoby jest szyfrowanie.

Keychain jest zaszyfrowanym kontenerem, który zawiera hasła do wielu aplikacji i bezpiecznych usług. Dane chronione są za pomocą struktury klas podobnej do tej używanej do szyfrowania plików. Elementy dodane do pęku kluczy są kodowane jako plist binarny i szyfrowane za pomocą 128-bitowego klucza AES dla każdego elementu.

UserDefaults są przechowywane jako zwykły tekst w pliku bundlename.plist na urządzeniu. Każdy, kto ma dostęp do urządzenia, może otworzyć lub skopiować ten plik i przeczytać niezaszyfrowane informacje.

Z tego powodu Keychain zdecydowanie bardziej nadaje się do przechowywania haseł, tokenów i innych danych uwierzytelniających.

Ochrona prywatności użytkowników to jeden z podstawowych elementów tworzenia aplikacji, dlatego tak ważne jest, aby poufne dane były bezpieczne.

Jakie zadania dla CoreData?

Pierwszym krokiem w pracy z podstawowymi danymi jest utworzenie pliku modelu danych. Celem jest zdefiniowanie struktury obiektów aplikacji, w tym ich typów, właściwości i relacji. Aby korzystać z Core Data, musisz następnie skonfigurować stack Core Data, który składa się z:

  • modelu obiektów zarządzanych (managed object model) – definiuje on strukturę danych,
  • trwałego koordynatora sklepu (persistent store coordinator) – obsługuje on połączenie z magazynem danych;
  • zarządzanego kontekstu obiektów (managed object context) – obsługuje on operacje tworzenia, odczytu, aktualizacji i usuwania obiektów.

Przykład

1) Lokalna biblioteka:

    • Bibliotekarz może dodawać lub usuwać książki.
    • Może filtrować książki według gatunku lub autora.
    • Może sortować książki według daty publikacji.
    • Może rezerwować książki.

2) Wokalista i jego utwory:

    • 2 encje: wokalista i utwór muzyczny.
    • Relacja jeden do wielu między nimi.

Przykładowy Manager dla Keychain

Podsumowanie

Trwałość danych jest w aplikacjach istotna. Dlatego wiele z nich korzysta z możliwości zapisywania danych lokalnie. Wybór odpowiedniej metody jest niezwykle ważny, ponieważ może wpływać na bezpieczeństwo, szybkość działania czy złożoność obsługi.

Property List świetnie nadają się do przechowywania małej ilości danych, a FileSystem sprawdzi się np. podczas buforowania elementów. Z kolei UserDefaults może być wykorzystywane do zapisywania preferencji użytkownika, podczas gdy Keychain zapewni bezpieczeństwo wszystkim danym, które tego wymagają. Core Data natomiast sprosta najbardziej złożonych zadaniom, wymagających wielu jednostek i relacji.

Wszystkie opcje mają zalety i ograniczenia, więc upewnij się, że wybierasz ten, który jest najbardziej odpowiedni w twoim przypadku.

Wojtek

Wojtek Byczkowski

iOS Developer

Dowiedz się więcej

Wycena projektu

Opowiedz nam o swoim projekcie i napisz, jak możemy Ci pomóc.

Dlaczego warto rozwijać z nami projekty?

Logo Mobile Trends Awards

Mobile Trends Awards 2021

Wygrana w kategorii
ŻYCIE CODZIENNE

Nagroda Legalnych Bukmacherów

Nagroda Legalnych Bukmacherów 2019

Najlepsza aplikacja mobilna

Mobile Trends Awards logo

Mobile Trends Awards 2023

Wygrana w kategorii
MCOMMERCE ROZWÓJ

23

opinie klientów

Clutch logo