할 일 추가 후 TableView에 나타나기까지 상당한 시간이 걸려서 사용자 경험을 저하시킨다.
즉, 사용자 생성 요청 -> 서버에 생성 요청 -> 성공하면 화면 갱신 순서로 진행되는 비관적 업데이트 방법입니다.
final class FirestoreManager {
private let fireManager = FirebaseManager()
private let dataBase = Firestore.firestore().collection("User")
func saveTodo(data: Todo) async -> Bool {
guard let uid = fireManager.getUID() else { return false }
do {
try await dataBase.document(uid)
.collection(data.date).document(data.id.uuidString).setData(
[
"id": data.id.uuidString,
"content": data.content,
"date": data.date,
"priority": data.priority,
"done": data.done,
"alarm": data.alarm ?? "nil"
]
)
print("Document successfully added!")
return true
} catch {
print("Error adding document: \(error.localizedDescription)")
return false
}
}
}
final class TodoManager {
private let storeManager = FirestoreManager()
func saveTodo(saveTodo: Todo) async -> Bool {
let result = Task {
if await storeManager.saveTodo(data: saveTodo) == true {
if CoreDataManager.saveTodoData(todo: saveTodo) { return true }
}
return false
}
return await result.value
}
}
@objc func didTappedAddTodoButton() {
guard let date = viewModel?.getDate,
let text = inputTodoTextField.text else { return }
if todoManager.textFieldIsFullWithBlank(text: text) == false {
let strDate = DateFormatter.formatTodoDate(date: date)
let todo = Todo(
content: text,
date: strDate
)
Task {
let saveResult = await todoManager.saveTodo(saveTodo: todo)
if saveResult == true {
tableView.reloadData()
} else {
showAlert()
}
}
}
inputTodoTextField.text?.removeAll()
addTodoButton.isEnabled = false
}
위의 과정을 진행함에 있어서 실패할 수 있는 가능성이 있기 때문에 최대한 안전하게 하려고 성공 여부에 따라 이후 작업을 진행시키려고 했다.
async/await
를 사용하여 비동기 처리를 한 것처럼 보이지만
Firestore에 저장 후 -> CoreData로 디바이스에 저장 후 -> TableView reload의 과정이 일련의 순서를 지키고 실행되고 있기 때문에 동기적 처리와 같이 동작해서 네트워크 속도가 느린 상황에서는 즉시 추가되지 않기 때문에 사용자 경험을 저하시키게 된다.
즉, 사용자 수정 요청 -> 화면 갱신 -> 서버에 수정 요청 순서로 진행하는 낙관적 업데이트 방법을 사용
final class FirestoreManager {
private let fireManager = FirebaseManager()
private let dataBase = Firestore.firestore().collection("User")
func saveTodo(data: Todo) async {
guard let uid = fireManager.getUID() else { return }
var retryCount = 0
while retryCount < 3 {
do {
try await dataBase.document(uid)
.collection(data.date).document(data.id.uuidString).setData(
[
"id": data.id.uuidString,
"content": data.content,
"date": data.date,
"priority": data.priority,
"done": data.done,
"alarm": data.alarm ?? "nil"
]
)
print("Document successfully added!")
return
} catch {
print("Error adding document: \(error.localizedDescription)")
retryCount += 1
}
}
print("Max retry count reached, document could not be added.")
}
}
final class TodoManager {
private let storeManager = FirestoreManager()
func saveTodo(saveTodo: Todo) -> Bool {
if CoreDataManager.saveTodoData(todo: saveTodo) {
Task {
await storeManager.saveTodo(data: saveTodo)
}
return true
}
return false
}
}
@objc func didTappedAddTodoButton() {
guard let date = viewModel?.getDate,
let text = inputTodoTextField.text else { return }
if todoManager.textFieldIsFullWithBlank(text: text) == false {
let strDate = DateFormatter.formatTodoDate(date: date)
let todo = Todo(
content: text,
date: strDate
)
let saveResult = todoManager.saveTodo(saveTodo: todo)
if saveResult == true {
tableView.reloadData()
} else {
showAlert()
}
}
inputTodoTextField.text?.removeAll()
addTodoButton.isEnabled = false
}
Todo 생성 버튼을 클릭하면 UI에 즉시 업데이트되는 것을 볼 수 있습니다!
유익한 자료 감사합니다.