- 키워드를 등록해 원하는 팝업 알림 받기 🔔
- 검색·필터로 보고 싶은 팝업 바로 찾기 🔎
- 달력에서 날짜별 팝업 일정 확인하기 📅
- 지도로 내 주변 팝업 한눈에 보기 🗺️
- 관심 팝업을 찜해 나만의 리스트로 관리하기 ⭐
| library | description |
|---|---|
| FirebaseSDK | FCM을 이용한 푸쉬 알림을 구현하기 위함 |
| KakaoSDK | 카카오 소셜 로그인 구현을 위함 |
| GoogleSDK | 구글 소셜 로그인 구현을 위함 |
| Moya | 추상화된 네트워크 레이어를 보다 간편하게 사용하기 위함 |
| Kingfisher | 이미지 캐싱 처리 및 UI 성능 개선을 위함 |
문제
여러 API가 순차적으로 호출되며 전체 로딩이 길어졌음해결
TaskGroup을 활용해 병렬 처리 구조로 전환성과
🔸 초기 로딩 시간 40% 단축
func getAllPopupData() async {
do {
try await withThrowingTaskGroup(of: (Int, [Popup]).self) { group in
group.addTask { (0, await self.getPersonalRandomPopupList()) }
group.addTask { (1, await self.getPersonalUpcomingPopupList()) }
group.addTask { (2, await self.getPersonalFilteredPopupList()) }
for try await (index, popups) in group {
await MainActor.run {
switch index {
case 0: self.bestPopups = popups
case 1: self.comingPopups = popups
case 2: self.gridPopups = popups
default: break
}
}
}
}
} catch {
Logger.e("❌ 로딩 실패: \(error)")
}
}문제
Moya는 completion 기반이라 async/await과 직접 호환되지 않아
API마다 동일한 변환 코드가 반복됨해결
withCheckedThrowingContinuation기반 공통 async 변환 래퍼 구현성과
🔸 Repository 전역에서 동일한 async 인터페이스 사용.
🔸 중복 코드 감소 + 유지보수성 향상
extension MoyaProvider {
func asyncRequest(_ target: Target) async throws -> Response {
try await withCheckedThrowingContinuation { continuation in
self.request(target) { result in
switch result {
case .success(let response):
continuation.resume(returning: response)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
}
// 호출 예시
let response = try await provider.asyncRequest(.getPopupList)문제
push / sheet / overlay 화면 전환 코드가 각 View에 흩어져 있어
네비게이션 흐름이 일관적이지 않고 유지보수가 어려웠음해결
Route 기반 Generic Coordinator 도입으로
모든 화면 이동을 동일한 호출 형태로 사용하도록 개선성과
🔸 push / sheet / overlay를 하나의 패턴으로 호출
🔸 화면이동 관련 상태 변수 70% 감소
🔸 일관된 네비게이션 흐름 확보 및 View 코드 간결화
class Coordinator<R: Hashable, S: Identifiable, O: Identifiable>: ObservableObject {
@Published var paths: [R] = []
@Published var sheet: S?
@Published var overlay: O?
func push(_ route: R) {
paths.append(route)
}
func present(_ sheet: S) {
self.sheet = sheet
}
func showOverlay(_ overlay: O) {
self.overlay = overlay
}
}
// 호출 예시
coordinator.push(.detail(popup)) // 화면 이동
coordinator.present(.regionSheet) // 시트
coordinator.showOverlay(.notification) // 오버레이