티스토리 뷰

기존 구현 화면

구조상 북마크 저장을 할 때 마다 추가적인 API 통신이 이루어 지므로,
사용자 입장에서 데이터 통신을 하고 있으니 잠시 기다려 달라는 의미로 Indicator 를 show하고, 데이터 통신이 종료되면 dismiss 하였습니다.

A total of 78 percent of consumers have felt negative emotions as a result of a slow or unreliable website.
출처: https://www.techradar.com/news/world-of-tech/roundup/consumers-dump-slow-websites-1080742

사용자 입장을 고려하여 Incidator를 구현하였지만, 오히려 너무 잦은 Indicator 남용으로 인해 사용자에게 스트레스를 줄 것이다 라는 생각이 들었습니다.

게다가 이번 프로젝트에 사용한 한국관광공사 API 는 가끔 서버통신이 잘 안될때가 있어서 잦은 Indicator 는 사용자 입장에서 더 답답할 수 있을 것...

그리하여 북마크 버튼은 Optimistic UI를 적용하여 리팩토링을 진행하였습니다.

Optimistic UI에서 고려할 점

  • 사용자의 액션에 대한 빠른 응답
  • 잠재적 실패에 대응

기존코드

@objc private func bookmarkButtonClickedInBottomCV(_ sender: UIButton) {
        SVProgressHUD.show()

        guard let data = viewModel.outputFestivalData.value?.response.body.items?.item?[sender.tag] else {
            return }


        if viewModel.repository.isBookmarked(contentId: data.contentid) {
            viewModel.repository.deleteBookmark(data: data)

            SVProgressHUD.dismiss(withDelay: 0.2)
            bottomCollectionView.reloadData()

        } else {

            viewModel.repository.addBookmark(id: data.contentid) { success in

                DispatchQueue.main.async {
                    if success {
                        SVProgressHUD.dismiss()
                    } else {
                        SVProgressHUD.showError(withStatus: "서버 오류")

                    }

                    self.bottomCollectionView.reloadData()
                }
            }
        }
    }
  • 기존코드는 버튼 클릭시, 데이터 통신이 끝나고 저장될때 까지 Indicator가 show 되며 서버 상태에 따라 사용자 입장에서는 답답함을 느낄 수 있습니다

개선된 코드 (Optimistic UI 적용)

@objc private func bookmarkButtonClickedInBottomCV(\_ sender: UIButton) {

    guard let data = viewModel.outputFestivalData.value?.response.body.items?.item?[sender.tag] else {
        return }
    // 북마크 상태 확인
    let isBookmarked = viewModel.repository.isBookmarked(contentId: data.contentid)

    // Optimistic UI 업데이트
    sender.setImage(UIImage(systemName: isBookmarked ? "bookmark" : "bookmark.fill"), for: .normal)

    // 북마크 상태에 따라 북마크 추가 또는 삭제
    if isBookmarked {
        viewModel.repository.deleteBookmark(data: data)
        // 삭제 후 UI 업데이트 필요 없음
    } else {
        viewModel.repository.addBookmark(id: data.contentid) { success in
            DispatchQueue.main.async {
                if !success {
                    // 요청 실패 시 UI 되돌리기
                    sender.setImage(UIImage(systemName: "bookmark"), for: .normal)
                    // 실패 피드백 제공
                }
            }
        }
    }
}
  • 개선된 코드는 버튼을 누르자마자 성공을 가정하고 버튼 이미지를 fill로 변경해주며,
    실패시에는 다시 되돌리는 형태로 구현하였습니다.
  • Optimistic UI 적용으로 사용자 입장에서 빠릿빠릿한 UI로 쾌적함을 느낄 수 있도록 개선하였습니다.

개선된 구현 화면

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
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 31
글 보관함