일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 계산기만들기
- 내배캠
- Storyboard Reference
- Xcode
- 알고리즘
- Flutter
- ListTile
- 코드스니펫
- ios
- DART
- attributedText
- 스파르타코딩클럽
- 날짜처리
- Swift
- pop up button
- 개발자
- 플러터
- UISlider
- 내일배움캠프
- 오토레이아웃
- Storyboard
- 커맨드라인툴
- todolist
- strikeThrough
- 메모장만들기
- URLSession
- userdefaults
- 앱개발
- pull down button
- Wil
- Today
- Total
이리메라 갖다가
[Swift] 메모 앱 만들기 심화 (7) : UserDefaults 로 데이터 저장하기 본문
스토리보드 없이 메모앱 만들기를 진행하고 있는데, Todo에 해당하는 프로퍼티를 최대한 간단하게 정의하였다.
struct Todo {
var todo: String
var isCompleted: Bool
}
기초부터 차근차근 해보려고 todo 내용과 완료여부만 정의했고, Todo를 관리할 Manager를 구조체로 정의하였다.
struct TodoManager {
static let userDefaults = UserDefaults.standard
// MARK: - Variables
static var todoList: [Todo] = [
Todo(todo: "킬링보이스 악뮤 보기", isCompleted: true),
Todo(todo: "개인 과제 코드로만 해보기", isCompleted: false)
]
// MARK: - Load
static func loadTodo() {
}
// MARK: - Add
static func addTodo(_ newTodo: Todo) {
var updatedTodoList = todoList
updatedTodoList.append(newTodo)
todoList = updatedTodoList
print(todoList)
}
// MARK: - Save
static func saveTodo(_ saveTodo: Todo) {
}
// MARK: - Delete
}
UserDefaults를 이용해서 간단하게 저장과 읽어오기를 구현하기 위해 addTodo 함수에 아래와 같은 코드를 추가했는데 오류가 발생했다.
userDefaults.set(todoList, forKey: "todoList")
ERROR: Attempt to insert non-property list object
아니 이게 뭔데...
너무나 당연하게 입력받는 Todo를 append 하듯이 set에 value로 넣었는데 UserDefaults는 기본 데이터 형식(property list)만 저장할 수 있다고 안된단다...
그렇다 UserDefaults는 Array나 Dictionary와 같은 복잡한 데이터 구조를 직접 저장하지 못하는 문제가 있는 것이다...
만약에 내가 의도한 것과 같이 배열의 형태로 저장하고 싶으면 Codable 프로토콜을 활용하여 데이터를 인코딩 및 디코딩해야 한다는 점이다.
그치만, Codable 프로토콜을 채택하지 않고 프로퍼티를 개별로 저장하면 될 것 같아서 아래와 같이 수정했다.
userDefaults.set(newTodo.todo, forKey: "todoTitle")
userDefaults.set(newTodo.isCompleted, forKey: "isCompleted")
새로 입력받는 Todo를 newTodo라고 정의하고 각 프로퍼티들을 별도로 저장해준다.
근데 여기서 문제가 있다.
프로퍼티들을 개별로 저장할 수는 있으나, 나중에 todoList를 load 할 때 이 데이터들을 다시 불러와서 Todo 객체로 조합해야 하는 것이다. 쉽게 말해서 또 작업이 추가된다는 뜻이다.
이렇게 분리된 저장 방식은 데이터를 관리하거나 활용하기에 복잡해져서 객체를 한번에 저장하거나 로드하기 위해서는 Codable 프로토콜을 사용하는 것이 더 효율적이다.
하지만 무시하고 loadTodo를 짰다.
static func loadTodo() {
if let todo = userDefaults.string(forKey: "todoTitle"),
let isCompleted = userDefaults.bool(forKey: "isCompleted") {
// 로드될 todoList를 정의하려고 했으나...
let loadTodoList = Todo(todo: todo, isCompleted: isCompleted)
}
}
바로 에러 발생
ERROR: Initializer for conditional binding must have Optional type, not 'Bool'
이 에러가 무엇인고 하니,
userDefaults.bool(forKey:) 메서드는 Bool 값을 반환하며, 이 값은 옵셔널이 아니기때문에 조건부 바인딩으로 추출할 수 없다는 말이다...
이 문제를 해결하기 위해서는 아래와 같이 코드를 수정할 수 있다.
저장
// 여러 개의 개별 값들을 저장(순서를 기억해야 함)
userDefaults.set(newTodo.todo, forKey: "todoTitle\(todoList.count)")
userDefaults.set(newTodo.isCompleted, forKey: "isCompleted\(todoList.count)")
// todoList 배열의 길이 갱신
let newCount = todoList.count + 1
userDefaults.set(newCount, forKey: "todoListCount")
// 로컬 배열 갱신
todoList.append(newTodo)
불러오기
// todoList 배열 불러오기
if let count = userDefaults.value(forKey: "todoListCount") as? Int {
for index in 0..<count {
if let todo = userDefaults.string(forKey: "todoTitle\(index)"),
let isCompleted = userDefaults.bool(forKey: "isCompleted\(index)") {
let loadedTodo = Todo(todo: todo, isCompleted: isCompleted)
todoList.append(loadedTodo)
}
}
}
그렇다.. 다시 수정해봤는데 겁나 복잡하다.....
..... Codable 프로토콜을 채택했다. 진작에 할껄.. 너무 쉽게 저장되네
// MARK: - Load
static func loadTodo() {
if let data = userDefaults.data(forKey: "todoList"),
let loadTodoList = try? JSONDecoder().decode([Todo].self, from: data) {
todoList = loadTodoList
}
}
// MARK: - Add
static func addTodo(_ newTodo: Todo) {
var updatedTodoList = todoList
updatedTodoList.append(newTodo)
todoList = updatedTodoList
saveTodo(newTodo)
loadTodo()
}
// MARK: - Save
static func saveTodo(_ saveTodo: Todo) {
if let saveData = try? JSONEncoder().encode(todoList) {
userDefaults.set(saveData, forKey: "todoList")
}
}
데이터를 저장하는 부분은 saveTodo 함수안에 구현하여 저장하고, loadTodo 함수에 저장된 데이터를 디코딩해서 불러온다.
이렇게 되면 todo를 추가할 때나 삭제할 때 해당 로직을 작성하고 saveTodo()만 호출해주면 너무나 쉽게 todo를 저장할 수 있다.
'TIL' 카테고리의 다른 글
[Swift] Youtube API 활용하여 앱 만들기 (1) : Youtube API 사용방법 (0) | 2023.09.04 |
---|---|
[Swift] 메모 앱 만들기 심화 (8) : TableView 살펴보기 (0) | 2023.09.01 |
[Swift] 메모 앱 만들기 심화 (6) : 스토리보드 없이 코드로 개발하기 초기 셋팅, 코드스니펫 만들기 (0) | 2023.08.30 |
[Swift] 메모 앱 만들기 심화 (5) : MVC 구조 (0) | 2023.08.29 |
[Swift] 메모 앱 만들기 심화 (4) : TableView 오류 해결하기 (4) | 2023.08.28 |