|
|
이융의 (iyungui) iOS Developer |
| GitHub Profile |
혼자서 기획부터 디자인, 개발까지 모든 과정을 진행했습니다.
iOS 클라이언트와 Node.js 백엔드 개발을 통해 전체 시스템 아키텍처에 대한 깊은 이해를 쌓을 수 있었습니다.
iOS 개발의 경우, Rx와 단방향 아키텍쳐에 대해서 깊이있게 이해할 수 있었습니다.
패킹(Packing)은 여행자를 위한 맞춤형 여행 준비물 추천 및 관리 서비스입니다. 여행 목적지, 기간, 테마 등 사용자 맞춤 정보를 바탕으로 최적화된 준비물 목록을 제공하여 여행 준비의 효율성을 높이고, 여행을 같이 가는 친구와 함께 실시간으로 준비 상황을 공유할 수 있는 iOS 애플리케이션입니다.
여행을 떠나기 전, 무엇을 챙겨야 할지 고민해도 막상 여행 중에 필요한 물건을 깜빡하는 상황이 있습니다. 패킹은 이를 해결하기 위해 개발 되었습니다.
📱 스크린샷
|
|
|
|
|
런치스크린 패킹 앱 런치스크린 |
여행 테마 선택 화면 여행 준비물 추천 하기 이전, 여행 테마(목적)을 선택하는 컬렉션 뷰 |
여행 상세 화면 여행지 사진, 참가자, 날씨, 준비물 섹션 확인 |
푸시 알림 화면 - 파티/친구 추가 알림 - 여행 전 날 날씨 체크 및 준비물 리마인더 |
1. 여행 준비물 맞춤 추천 시스템 목적지, 기간, 테마(바다/등산/쇼핑 등) 기반 최적화된 준비물 추천 날씨와 여행 목적에 맞춤화된 옷차림과 필수품 제안 카테고리별 체계적인 체크리스트 제공
2. 실시간 준비물 공유 기능 여행 파티원 초대 시스템을 통한 체크리스트 실시간 공유 공용 준비물과 개인 준비물 구분 관리
3. 스마트 리마인더 기능 (APNS) 여행지 위치 기반 날씨 정보 자동 연동 출발 전 준비물 점검 알림 서비스 기상 특이사항 발생 시 맞춤형 알림 제공
🎯 추가 스크린샷
- 여행지 사진은 unsplash image api를 사용하여, 해당 여행지(도시)의 사진을 바로 제공합니다.
- 날씨 정보는 openweathermap api 를 사용하여 해당 기간, 목적지의 날씨 정보를 제공합니다.
- 회원탈퇴한 유저의 경우, 친구목록에 Unknown User로 뜨게 하는 예외 처리
- 프로필 화면 - Social Login Type, intro 등 기본적인 프로필 정보를 표시
- 그 외 개인정보처리방침, 서비스 이용약관 등의 정보는 노션에 연결 [WKWebView 사용]
- Swift 6.1+
- UIKit + SwiftUI 구현
- ReactorKit (단방향 데이터 흐름 아키텍처)
- RxSwift & RxCocoa
- RxDataSources
- Swift concurrency task, async await (SwiftUI View에 사용)
- Kingfisher (이미지 캐싱)
- KeychainSwift (토큰 데이터 관리)
- UIKit Codebase (No storyboard)
- UICollectionView, UITableView 등
- Node.js & Express
- MongoDB
- JWT 기반 인증 시스템
- Socket.io (실시간 통신)
- Passport.js (OAuth 인증)
- SendGrid (이메일 인증 시 사용), AWS S3 (이미지 저장), Unsplash API, OpenWeather API
- 로그인 화면의 경우에는 MVVM in-out으로, 나머지 UIKit 화면은 ReactorKit을 통해 단방향 데이터 흐름을 관리하도록 하였습니다.
- 여행 상세 화면인 JourneyDetailView의 경우에는 SwiftUI로 구현하였습니다. UIKit 프로젝트에서 UIHostingController로 보여주었습니다. 간단한 단일 뷰 였기 때문에 그리고 SwiftUI의 철학 상, 따로 뷰모델을 굳이 만들지 않았습니다.
- AppDelegate, SceneDelegate
- 네트워크: API Client, Endpoints, Error 처리
- 스토리지: KeychainManager (액세스 토큰, 리프레시 토큰), UserManager
- Models (엔티티)
- Services (비즈니스 로직)
- ViewController (UI 담당)
- Reactor (상태 관리, 비즈니스 로직)
- JourneyCreatorCoordinator: 여행 생성 프로세스
- AuthCoordinator: 인증 사용자 유무 네비게이션 프로세스
- iOS 17.6+
- Xcode 16.0+
- SPM (RxSwift, RxDataSources, KeychainAccess, ReactorKit, RxCocoa)
# 저장소 클론
git clone https://github.com/Packing-App/Packing-iOS.git
# 디렉토리 이동
cd Packing
# Xcode에서 .xcodeproj 파일 열기
open Packing.xcodeproj대표적인 트러블 슈팅 내용은 노션에서 자세히 볼 수 있습니다.
ReactorKit을 도입하여 View와 비즈니스 로직을 명확히 분리했습니다. Action -> Mutation -> State -> View 흐름으로 데이터 변화를 한눈에 보기 쉽게 관리하도록 했습니다.
final class ProfileViewReactor: Reactor {
// 사용자 액션 정의
enum Action {...}
// 상태 변경 중간 단계 이벤트
enum Mutation {...}
// 화면의 상태 정의
struct State {...}
let initialState: State
// 뷰로부터 Action을 받아 Mutation으로 변환
func mutate(action: Action) -> Observable<Mutation> {...}
// Mutation를 받아 State를 변경
func reduce(state: State, mutation: Mutation) -> State {...}
}final class ProfileViewController: UIViewController, View {
func bind(reactor: ProfileViewReactor) {
// Action 바인딩
button.rx.tap
.subscribe(onNext: { [weak self] _ in })
.disposed(by: disposeBag)
// State 바인딩
reactor.state.map { $0.isLoading }
.subscribe(onNext: { [weak self] _ in })
.disposed(by: disposeBag)
}
}Observable 스트림에서 발생할 수 있는 Reentrancy 문제를 해결하기 위해 publishRelay, MainScheduler 스케줄러 활용으로 안정적인 비동기 처리를 구현했습니다. -- (UI 변경로직은 메인스레드에서, 네트워크 통신은 백그라운드 스레드에서 처리)
AccessToken과 RefreshToken을 활용한 보안 인증 시스템을 구현했습니다. 만료된 토큰의 경우에는 자동 갱신 처리를 하여, 자동 로그인을 구현하였으며, 토큰 데이터는 KeychainManager를 통해 안전하게 관리했습니다.
UIDevice.current.userInterfaceIdiom == .pad 을 사용하여, 적응형 레이아웃을 구현했습니다. 이를 통해 iPhone SE부터 iPhone pro max, 그리고 iPad 디바이스에서도 최적화된 사용자 경험을 제공하도록 했습니다.









