Skip to content

jieun0330/WaveEcho

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📨 WaveEcho(파도메아리)

lslpapplogo_125

소중한 메시지를 담은 쪽지를 바다 위로 띄워 다른 사람들과 쪽지를 전달하며 소통할 수 있는 앱

  • 유저 관리 회원가입 / 로그인 / 로그아웃 / 회원탈퇴
  • 게시글 및 댓글 게시글 작성 및 삭제 / 댓글 생성 및 삭제
  • 거래 기능 게시글 작성 횟수 결제 / 결제 내역 조회

⚒️ 스크린샷

Group 517167395


🪚 시연 영상

유저 관리

회원가입 로그인 로그아웃 회원탈퇴
회원가입 로그인 로그아웃 회원탈퇴

게시글 및 댓글 관리

게시글 작성 게시글 조회 게시글 삭제 댓글 작성
포스트작성 포스트조회 게시글 삭제 댓글 작성

결제 관리

결제 버튼 클릭 결제 결제 완료 결제 내역 조회
결제 버튼 클릭 결제 결제완료 결제 내역

🔨 개발기간

2024년 4월 10일 ~ 5월 5일 (약 3주, 업데이트 진행중)


🛠️ 사용기술 및 라이브러리

UIKit(Code Base) MVVM RxSwift SnapKit Kingfisher Alamofire Toast


🔧 구현 고려사항

  • RxSwift를 사용해 Reactive Programming을 통한 비동기 데이터 스트림 관리
  • RxSwift Single과 TargetType 프로토콜 네트워크 요청 로직 구현
  • Alamofire interceptor를 사용한 JWT 토큰 기반 회원 인증 로직 개발
  • RxSwift Driver로 메인 스레드에서 안전한 UI 업데이트 보장
  • PG 결제 시스템 통합 및 영수증 검증 처리
  • Multipart Form Data를 활용한 이미지 업로드 기능 개발
  • Class Deinit 및 Instruments 분석을 통해 Memory Leak 방지
  • Input/Output 패턴을 활용해 단방향 데이터 바인딩 구조 설계
  • APIError와 CallType 구조를 통해 새로운 API 호출 및 에러 케이스 확장 용이
  • BaseViewController로 공통 기능 통합 및 코드 재사용성 향상

⛏️ Trouble Shooting

❌ 문제 상황

댓글 작성 후 화면 전환시 댓글 업데이트 문제

⭕️ 해결 방법

  • protocol을 사용하여 댓글 데이터 전달
  • 댓글 작성이 완료되었을 때 delegate를 통해 데이터 업데이트
// ReplyViewController
protocol fetchComment: AnyObject {
    func fetchDone(data: CommentData)
}

final class ReplyViewController: BaseViewController {
    
    weak var delegate: fetchComment?
// PopupViewController
extension PopupViewController: fetchComment {
    func fetchDone(data: CommentData) {
        var value = behaviorModel.value
        value.comments.insert(data, at: 0)
        behaviorModel.accept(value)
    }
}

❌ 문제 상황

이미지 용량 압축 작업을 하지 않아 이미지 업로드 실패

⭕️ 해결 방법

  • UIImage에는 jpeg Data로 바꾸어주는 메소드가 있어서 한 줄의 코드로 변경 가능
  • compressionQuality에는 압축률을 전달
extension WritePostViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        
        let itemProvider = results.first?.itemProvider
        
        if let itemProvider = itemProvider,
           itemProvider.canLoadObject(ofClass: UIImage.self) {
            itemProvider.loadObject(ofClass: UIImage.self) { image, error in
                DispatchQueue.main.async {
                    let realImage = image as? UIImage
                    let imagePng = realImage?.jpegData(compressionQuality: 0.3)
                    self.imageData.accept(imagePng!)
                    self.mainView.presentPhotoView.image = image as? UIImage
                }
            }
        }
    }
}

❌ 문제 상황: 에러 응답 코드 흐름 이해
서버로부터 받는 응답코드 419와 418의 처리 방식을 이해하는 것이 어려웠다.
419 상태 코드를 만났을 때, 418 상태 코드를 만나지 않고는 접할 수 없다는 점이었다.

⭕️ 해결 방법

  • 먼저, 419와 418 응답 코드의 처리방법을 명확히 이해
  • APIManager에 리프레시 토큰 만료(418) 상태를 처리할 수 있는 RefreshToken interceptor 로직 구현
  • 로그아웃 과정을 사용자에게 알리기 위해 MyPostViewController에서 로그아웃 알림과 함께 화면 전환 로직 구현
// MyPostViewController
private lazy var logout = UIAction(title: "로그아웃",
                                       image: UIImage(systemName: "rectangle.portrait.and.arrow.right"),
                                       handler: { [weak self] _ in
        guard let self else { return }
        makeAlert(alertTitle: "로그아웃 하시겠습니까?", alertMessage: nil) { [weak self] completeAction in
            guard let self else { return }
            view.makeToast("로그아웃되었습니다", duration: 1, position: .center) { [weak self] didTap in
                guard let self else { return }
                UserDefaultsManager.shared.accessToken.removeAll()
                setVC(vc: LoginViewController())
            }
        }
    })

🔧 추후 업데이트 사항

  • UserDefaults enum 활용 리팩토링
  • cell 속성 리팩토링
  • 메모리 누수 확인

👏🏻 회고

프로젝트를 시작하기 전까지, 응답 코드에 대한 처리, Router enum 활용, HTTP 메서드 뿐 아니라 리프레시 토큰의 만료와 갱신 관리까지 이렇게 많은 부분을 한 번에 다루어야 하는 경험은 전무했다. 이 모든 부분을 어디서 어떻게 시작해야 할지 막막했다. 하지만 이 프로젝트를 통해 실제로 서버 요청을 보내고 받아보며 서비스를 확장해 나가는 과정은 좋은 경험이었다. 서버 통신을 구현하며, 각 HTTP 메서드(GET, POST 등)의 사용법을 익혔고, REST API 설계 원칙에 대해 이해할 수 있었다. 특히 이번 프로젝트에서 처음으로 리프레시 토큰 개념에 대해 깨달았다. 액세스 토큰이 만료되었을 때 어떻게 토큰을 갱신할 수 있을지에 대한 고민은 프로젝트를 통해 해결해 나가는 큰 도전이었다. 이 과정에서, 토큰 갱신 로직을 구현하고, 이를 프로젝트의 다른 부분과 통합하는 방법을 배웠다.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages