Search code examples
swiftuserdefaults

Best approach to use UserDefaults


I just started to learn swift, decided to make the first todo app and I had a question. It is necessary to save all data during any user actions: creating, changing or deleting a task. Calling a method to save data each time is a bad approach. What can you recommend?

func addItem(itemName: String, isCompleted: Bool = false) {
   tasks.append(Tasks(taskName: itemName, isCompleted: isCompleted))
   saveData()
}

I store tasks in a structure. Before using the structure, I used computed property like this:

var ToDoItems: [[String: Any]] {
   set {
     UserDefaults.standard.set(newValue, forKey: "ToDoDataKey")
     UserDefaults.standard.synchronize()
   }

   get {
     if let userData = UserDefaults.standard.array(forKey: "ToDoDataKey") as? 
 [[String: Any]] {
       return userData
   } else {
     return []
   }
 }
}

Solution

  • In didSet of tasks array, you can simply set the current array elements in UserDefaults.

    struct Task: Codable {
        let taskName: String
        let isCompleted: Bool
    }
    
    var tasks = [Task]() {
        didSet {
            let data = try? JSONEncoder().encode(tasks)
            UserDefaults.standard.set(data, forKey: "ToDoDataKey")
        }
    }
    
    func addItem(itemName: String, isCompleted: Bool = false) {
        tasks.append(Task(taskName: itemName, isCompleted: isCompleted))
    }
    

    This will ensure that the data in UserDefaults is synchronized with that currently in the memory.

    And fetch the data only in viewDidLoad() where the data will be loaded for the first time.

    func fetchTasks() -> [Task] {
        if let data = UserDefaults.standard.data(forKey: "ToDoDataKey"), let tasks = try? JSONDecoder().decode([Task].self, from: data) {
            return tasks
        }
        return []
    }
    

    Call fetchTasks() in viewDidLoad().