How many solution save local data on mobile for iOS Developer.

Papon Smc
TakoDigital
Published in
6 min readJun 30, 2023

--

*** This section try use english

Introduction:

Data persistence plays a crucial role in iOS app development, enabling applications to store and retrieve data across different sessions. In this blog post, we will explore various data persistence techniques available in Swift, including UserDefaults, Keychain, saving files to disk, Core Data, SQLite, Property Lists, and SwiftData. We’ll delve into their advantages, limitations, and provide sample code to demonstrate their usage. Let’s get started!

iOS Data Persistence in Swift

  • UserDefaults
  • Keychain
  • Saving files to disk
  • Core Data
  • SQLite
  • Property Lists
  • SwiftData

UserDefaults

UserDefaults is a lightweight and straightforward approach to store small amounts of data, such as user preferences and settings. It relies on key-value pairs and is suitable for storing simple data types like strings, numbers, and booleans.

Advantages:

  • Easy to use and implement.
  • Automatically handles serialization and deserialization.
  • Ideal for storing app configurations and user preferences.

Limitations:

  • Not suitable for storing large amounts of data.
  • Lacks complex querying capabilities.
  • Does not provide encryption or security features.

Sample Code:

// Writing data to UserDefaults
UserDefaults.standard.set("John Doe", forKey: "userName")
UserDefaults.standard.set(25, forKey: "userAge")
UserDefaults.standard.set(true, forKey: "isSubscribed")
UserDefaults.standard.synchronize()

// Reading data from UserDefaults
let name = UserDefaults.standard.string(forKey: "userName")
let age = UserDefaults.standard.integer(forKey: "userAge")
let isSubscribed = UserDefaults.standard.bool(forKey: "isSubscribed")

Keychain

sample

The Keychain is a secure storage mechanism provided by iOS for sensitive information such as passwords, authentication tokens, and encryption keys. It ensures data encryption and protection against unauthorized access.

Advantages:

  • Offers a secure storage option for sensitive data.
  • Provides data encryption and protection.
  • Enables sharing data between apps from the same developer.

Limitations:

  • More complex to implement compared to UserDefaults.
  • Limited storage capacity.
  • Not suitable for storing large data sets.

Sample Code:

import Security

// Writing data to Keychain
let keychainQuery: [CFString: Any] = [
kSecClass: kSecClassGenericPassword,
kSecAttrAccount: "myAccount",
kSecValueData: "myPassword".data(using: .utf8)!
]
let status = SecItemAdd(keychainQuery as CFDictionary, nil)

// Reading data from Keychain
let readQuery: [CFString: Any] = [
kSecClass: kSecClassGenericPassword,
kSecAttrAccount: "myAccount",
kSecMatchLimit: kSecMatchLimitOne,
kSecReturnData: true
]
var item: CFTypeRef?
let readStatus = SecItemCopyMatching(readQuery as CFDictionary, &item)
let passwordData = item as! Data
let password = String(data: passwordData, encoding: .utf8)

Saving Files to Disk

Saving files to disk is a common approach for storing large data sets, such as images, videos, or documents. iOS provides a variety of options, including saving files in the app’s sandboxed directories or using external storage providers like iCloud or Dropbox.

Advantages:

  • Suitable for storing large data sets.
  • Provides flexibility in organizing and managing files.
  • Allows easy sharing of files with other apps.

Limitations:

  • Requires managing file paths and directories.
  • Not designed for structured data storage.
  • May require additional effort for synchronization and backup.

Sample Code:

// Writing data to a file
let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("data.txt")
let text = "Hello, World!"
try text.write(to: fileURL, atomically: true, encoding: .utf8)

// Reading data from a file
let fileContent = try String(contentsOf: fileURL)

Core Data

Core Data is a powerful framework that provides object-oriented data persistence. It allows you to create, read, update, and delete data using a managed object model, providing advanced querying and relationship management capabilities.

Advantages:

  • Provides an object-oriented approach to data persistence.
  • Supports complex data models and relationships.
  • Offers data synchronization and conflict resolution.

Limitations:

  • Requires a learning curve to understand its concepts and APIs.
  • Can be overkill for simple data storage needs.
  • Not suitable for storing large binary data.

Sample Code:

import CoreData

// Writing data to Core Data
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext

let entity = NSEntityDescription.entity(forEntityName: "Person", in: context)!
let person = NSManagedObject(entity: entity, insertInto: context)
person.setValue("John Doe", forKey: "name")
person.setValue(25, forKey: "age")

try! context.save()

// Reading data from Core Data
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
let persons = try! context.fetch(fetchRequest) as! [NSManagedObject]

for person in persons {
let name = person.value(forKey: "name") as! String
let age = person.value(forKey: "age") as! Int
print("Name: \(name), Age: \(age)")
}

SQLite

SQLite is a lightweight and embedded relational database that offers a SQL-based interface for data persistence. It is suitable for applications that require structured data storage and advanced querying capabilities.

Advantages:

  • Supports complex querying using SQL.
  • Offers efficient data retrieval and manipulation.
  • Suitable for applications with structured data needs.

Limitations:

  • Requires understanding SQL and database concepts.
  • Lacks the scalability of server-based databases.
  • More complex to set up and manage compared to other persistence options.

Sample Code:

import SQLite3

// Creating and connecting to a SQLite database
var db: OpaquePointer?

if sqlite3_open(fileURL.path, &db) != SQLITE_OK {
print("Error opening database!")
}
else {
print("Database opened successfully!")

// Perform database operations
// ...

sqlite3_close(db)
}

Property Lists

Property lists (or plists) are a lightweight and simple way to store structured data, including arrays and dictionaries. They are often used for configuration files or small data sets.

Advantages:

  • Easy to work with for small, structured data.
  • Supports different data types and hierarchies.
  • Can be easily serialized and deserialized.

Limitations:

  • Not suitable for storing large or complex data.
  • Lacks querying and relational capabilities.
  • Limited flexibility for handling data updates.

Sample Code:

// Writing data to a property list
let data: [String: Any] = [
"name": "John Doe",
"age": 25,
"isSubscribed": true
]
let plistURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("data.plist")
(data as NSDictionary).write(to: plistURL, atomically: true)

// Reading data from a property list
let plistData = NSDictionary(contentsOf: plistURL) as! [String: Any]
let name = plistData["name"] as! String
let age = plistData["age"] as! Int
let isSubscribed = plistData["isSubscribed"] as! Bool

SwiftData

SwiftData makes it easy to persist data using declarative code. You can query and filter data using regular Swift code. And it’s designed to integrate seamlessly with SwiftUI.

Create models with Swift

Model your data using regular Swift types with @Model, with no additional files or tools to manage. SwiftData can automatically infer many relationships and you can use clear declarations like @Attribute(.unique) to describe constraints. Like SwiftUI, the source of truth is in your code.

@Model class Recipe {  @Attribute(.unique) var name: String  var summary: String?  var ingredients: [Ingredient] }

Automatic persistence

SwiftData builds a custom schema using your models and maps their fields efficiently to the underlying storage. Objects managed by SwiftData are fetched from the database when needed and automatically saved at the right moment, with no additional work on your part. You can also take full control using the ModelContext API.

Integrates with SwiftUI

Use @Query in your SwiftUI views to fetch data. SwiftData and SwiftUI work together to provide live updates to your views when the underlying data changes, with no need to manually refresh the results.

@Query var recipes: [Recipe] var body: some View {  List(recipes) { recipe in   NavigationLink(recipe.name, destination: RecipeView(recipe))  } }

Swift-native predicates

Query and filter your data using expressions that are type-checked by the compiler so you can catch typos and mistakes during development. Predicates provide compile-time errors when your expressions can’t be mapped to the underlying storage engine.

let simpleFood = #Predicate<Recipe> { recipe in  recipe.ingredients.count < 3 }

CloudKit syncing

Your data can be stored in files using DocumentGroup and synced via iCloud Drive, or you can use CloudKit to sync data between devices.

Compatible with Core Data

SwiftData uses the proven storage architecture of Core Data, so you can use both in the same app with the same underlying storage. When you’re ready, Xcode can convert your Core Data models into classes for use with SwiftData.

Conclusion

After I understand about data persistence each type I try summary my opinion in table same below image

https://docs.google.com/spreadsheets/d/1hPIPQ7bJpqRGxJz-8peEuQI0bmlGWfsX4134e3ovMTU/edit?usp=sharing

but in some ability if I not have reference data I remark “not sure” because data reference I invest is conflict when I do some workshop then prove session I will update again.

Best Regrads,
Papon Supamongkonchai
iOS Developer

--

--

Papon Smc
TakoDigital

IOS Developer like learn for develop skill my self road to specialist Mobile developer and can give consult every bussiness , tech and architect question