Course Lessons
Lesson 3 of 4
Data Management in iOS
Master data persistence in iOS apps using UserDefaults, Core Data, and modern data modeling patterns with SwiftUI.
32 minutes
Data Management in iOS
Effective data management is crucial for building robust iOS applications that persist user data and maintain state.
Data Persistence Options
iOS provides several ways to store data:
- UserDefaults: Simple key-value storage for preferences
- Core Data: Apple's object graph and persistence framework
- File System: Direct file reading and writing
- Keychain: Secure storage for sensitive data
- CloudKit: Sync data across user devices
UserDefaults
Perfect for simple preferences and settings:
let defaults = UserDefaults.standard
defaults.set("Sarah", forKey: "userName")
let name = defaults.string(forKey: "userName")
Best for:
- User preferences and settings
- Small amounts of data
- Simple key-value pairs
Core Data
Apple's powerful framework for complex data models:
- Object-oriented database
- Relationships between entities
- Query and filter capabilities
- Automatic change tracking
- iCloud synchronization support
Data Models with SwiftUI
SwiftUI works seamlessly with data models:
- Use
@Statefor simple local data - Use
ObservableObjectfor complex models - Leverage
@Publishedfor automatic UI updates - Use
@FetchRequestwith Core Data
Codable Protocol
Swift's Codable makes JSON serialization easy:
struct User: Codable {
let name: String
let email: String
}
- Automatically encode/decode JSON
- Works with UserDefaults and file storage
- Type-safe data transformation
Best Practices
- Choose the right storage solution for your needs
- Keep data models simple and focused
- Use Codable for JSON serialization
- Consider data privacy and security
- Implement proper error handling
- Test data persistence thoroughly
Code Example
import SwiftUI
// Codable Data Model
struct Task: Identifiable, Codable {
let id: UUID
var title: String
var isCompleted: Bool
var createdAt: Date
init(title: String) {
self.id = UUID()
self.title = title
self.isCompleted = false
self.createdAt = Date()
}
}
// Observable ViewModel
class TaskManager: ObservableObject {
@Published var tasks: [Task] = [] {
didSet {
saveTasks()
}
}
private let tasksKey = "savedTasks"
init() {
loadTasks()
}
func addTask(_ title: String) {
let newTask = Task(title: title)
tasks.append(newTask)
}
func toggleTask(_ task: Task) {
if let index = tasks.firstIndex(where: { $0.id == task.id }) {
tasks[index].isCompleted.toggle()
}
}
private func saveTasks() {
if let encoded = try? JSONEncoder().encode(tasks) {
UserDefaults.standard.set(encoded, forKey: tasksKey)
}
}
private func loadTasks() {
if let data = UserDefaults.standard.data(forKey: tasksKey),
let decoded = try? JSONDecoder().decode([Task].self, from: data) {
tasks = decoded
}
}
}
// SwiftUI View
struct TaskListView: View {
@StateObject private var taskManager = TaskManager()
@State private var newTaskTitle = ""
var body: some View {
NavigationView {
VStack {
HStack {
TextField("New task", text: $newTaskTitle)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button("Add") {
taskManager.addTask(newTaskTitle)
newTaskTitle = ""
}
.disabled(newTaskTitle.isEmpty)
}
.padding()
List(taskManager.tasks) { task in
HStack {
Image(systemName: task.isCompleted ? "checkmark.circle.fill" : "circle")
.foregroundColor(task.isCompleted ? .green : .gray)
Text(task.title)
.strikethrough(task.isCompleted)
}
.onTapGesture {
taskManager.toggleTask(task)
}
}
}
.navigationTitle("My Tasks")
}
}
}