{"id":26739411,"url":"https://github.com/jeon0976/ios-cleanarchitecture-sample","last_synced_at":"2026-04-20T03:38:15.294Z","repository":{"id":281590355,"uuid":"945732555","full_name":"Jeon0976/iOS-CleanArchitecture-Sample","owner":"Jeon0976","description":"모듈화가 적용된 Clean Architecture iOS 샘플 앱입니다.","archived":false,"fork":false,"pushed_at":"2025-03-25T04:46:00.000Z","size":485,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T05:28:32.596Z","etag":null,"topics":["cleanarchitecture","combine","coordinator","dicontainer","ios","lrucache","mvvm","protocol-oriented-programming","swiftconcurrency","swiftui","tuist","uikit","unittest","xctest"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jeon0976.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-10T03:19:04.000Z","updated_at":"2025-03-25T04:46:03.000Z","dependencies_parsed_at":"2025-03-10T05:20:08.807Z","dependency_job_id":null,"html_url":"https://github.com/Jeon0976/iOS-CleanArchitecture-Sample","commit_stats":null,"previous_names":["jeon0976/cleanarchitecture-example","jeon0976/ios-cleanarchitecture-sample"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeon0976%2FiOS-CleanArchitecture-Sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeon0976%2FiOS-CleanArchitecture-Sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeon0976%2FiOS-CleanArchitecture-Sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jeon0976%2FiOS-CleanArchitecture-Sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jeon0976","download_url":"https://codeload.github.com/Jeon0976/iOS-CleanArchitecture-Sample/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245969569,"owners_count":20702245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cleanarchitecture","combine","coordinator","dicontainer","ios","lrucache","mvvm","protocol-oriented-programming","swiftconcurrency","swiftui","tuist","uikit","unittest","xctest"],"created_at":"2025-03-28T04:28:46.495Z","updated_at":"2026-04-20T03:38:15.246Z","avatar_url":"https://github.com/Jeon0976.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CleanArchitecture-Example\n\u003e Tuist를 사용한 모듈식 설계와 클린 아키텍처를 준수한 iOS 샘플 애플리케이션입니다. \n\n\u003cimg src=\"/Images/image.png\"\u003e\n\n### 주요 기능\n- Github 인증을 통한 로그인 기능\n- Github 사용자 검색 및 상세 결과 표시\n- 개인 정보 및 로그아웃 기능\n   \n### 개발 환경 \n- Tuist 4.43.1 활용하여 모듈화 적용 \n- Swift 5.x, iOS 16.0, XCode 14.0\n--- \n## 모듈 구조 설명 \n\u003cimg src=\"graph.png\"\u003e\n\n### 핵심 모듈 레이어\n- **APP**\n    - 다른 모든 모듈을 통합하고 앱 최초 진입점을 제공하는 핵심 모듈입니다. \n    - 의존성: Data, Presentation, Shared\n    - 책임\n        1. 애플리케이션 생명주기 관리 \n        2. 초기 네비게이션 설정\n        3. 초기 의존성 등록 \n- **Shared**\n    - 모든 모듈에서 공유되는 공통 유틸리티, 확장 및 헬퍼 모듈입니다.\n    - 의존성: 없음.\n    - 책임\n        1. 확장 함수\n        2. 유틸리티 클래스\n- **DependencyInjection**\n    - 애플리케이션 전반에 걸친 의존성 주입을 위한 인프라 제공 모듈입니다.\n    - 의존성: 없음.\n    - 책임: \n        1. 의존성 컨테이너 구현\n        2. 서비스 등록\n### 클린 아키텍처 레이어\n- **Presentation**\n    - 프레젠테이션 로직과 사용자 인터페이스 컴포넌트를 구현하는 UI 레이어입니다. \n    - 의존성: DependencyInjection, Domain, Shared\n    - 책임\n        1. ViewControllers\n        2. ViewModels \n        3. UI 컴포넌트\n- **Domain**\n    - 유스케이스, 엔티티 및 저장소 인터페이스를 포함하는 비즈니스 로직 레이어입니다.\n    - 의존성: DependencyInjection, Core, Shared \n    - 책임\n        1. 비즈니스 엔티티\n        2. 유스케이스\n        3. 저장소 인터페이스\n- **Data**\n    - Domain 레이어에 정의된 저장소 인터페이스를 구현하는 레이어입니다. \n    - 의존성: DependencyInjection, Domain, Shared\n    - 책임\n        1. 네트워크 통신\n        2. 로컬 스토리지 \n        3. DTO 및 추상화 \n- **Core**\n    - 핵심 비즈니스 로직 및 인프라 모듈입니다.\n    - 의존성: DependencyInjection, Shared\n    - 책임\n        1. 키체인 저장소 \n        2. 핵심 비즈니스 \n--- \n## 아키텍처 설명 \n\u003cimg src=\"/Images/Group.png\"\u003e\n\n### 레이어 분리 및 의존성 규칙 \n- 의존성이 안쪽으로만 향하는 클린 아키텍처 의존성 규칙을 따르고 있습니다.\n1. **외부 레이어**\n    - UI 및 Data (App, Presentation, Data)\n    - 중간 레이어를 참조하지만 중간 레이어에서는 참조되지 않음\n2. **중간 레이어**\n    - 애플리케이션 비즈니스 규칙 (Domain)\n    - 유스케이스 및 저장소 인터페이스 \n3. **내부 레이어**\n    - Keychain Storage, 핵심 공통 비즈니스로직 \n    - 다른 레이어에 대한 의존성 없음\n### 주요 이점 \n- 테스트 용이성\n    - 각 레이어를 독립적으로 테스트가 가능하도록 설계되어 있습니다. \n- 유지보수성\n    - 한 레이어의 변경이 다른 레이어에 영향을 크게 미치지 않습니다.\n- 유연성\n    - 외부 레이어의 구현을 쉽게 교체가 가능합니다.\n- 확장성\n    - Protocol을 통한 통신으로 기존 코드를 수정하지 않고 새로운 기능을 추가할 수 있습니다.\n- 관심사 분리 \n    - 각 모듈은 자신만의 특정 책임을 갖고 있습니다. \n\n### 단점 \n- 모듈 비대화\n    - 서비스가 확장됨에 따라 각 레이어 모듈의 크기가 과도하게 커질 수 있어 코드 관리와 빌드 시간에 부정적 영향을 미칠 수 있습니다. \n- 테스트 세분화 제한\n    - 기능이 확장될수록 특정 화면이나 기능 단위로 격리된 테스트를 수행하기 어려워집니다. \n\n\n#### 향후 개선 방향 \n- TMA(The Modular Architecture) 도입\n    - 현재의 레이어를 기반에서 기능 중심 모듈화(Micro Feature Architecture)로 전환하여 독립적인 기능 단위의 모듈을 구성할 계획입니다. \n- 수평적 모듈화 적용 \n    - 클린 아키텍처의 수적적인 레이어를 유지하면서 기능별 수평 모듈화를 통해 독립적인 피처, 도메인 모듈을 구성함으로써 모듈 간 의존성을 명확히 하고 테스트 용이성을 향상 시킬 것입니다.\n- 업그레이드 버전\n    - 개선된 아키텍처 패턴은 아래의 링크에서 확인할 수 있습니다. (구현 x, 예정 사항)\n    - https://github.com/Jeon0976/TheModularArchitecture-Example\n--- \n## 주요 기능 설명 \n\n### Github 인증 및 토큰 관리 \n- Github OAuth 기반 인증 시스템이 레이어별로 구현되어 있습니다.\n- Core 레이어에서 TokenStroage 프로토콜을 통해 토큰의 저장/조회/삭제 기능을 제공합니다. \n- Domain 레이어의 GithubTokenUseCase는 이 TokenStorage를 활용해 토큰을 관리하고  리포지토리 인터페이스를 통해 API 통신을 요청합니다.\n- Presentation 레이어에서 ViewModel이 사용자 이벤트를 Combine으로 처리하여 UseCase를 호출하고 Coordinator가 인증 완료 후 화면 전환을 담당합니다. \n \n### 사용자 검색 기능 \n- Domain 레이어는 사용자 검색에 대한 페이지 기능을 담당하고 있습니다. \n- Data 레이어의 SearchUserRepository는 Github API와 통신하여 검색 결과를 가져오고 PosterImageRepository는 사용자 아바타 이미지를 처리하고 있습니다. \n- 이미지는 PosterLRUCacheStorage를 통해 캐시되고 있습니다. \n- Presentation 레이어에서는 SearchUserViewModel이 SearchUserUseCase의 페이징된 Entity를 불러와 해당 결과를 Combine을 활용해 표시하고 있습니다. \n\n### 프로필 관리 \n- 주요 핵심 기능은 사용자 검색 기능과 동일하게 수행되고 있습니다. \n\n### DI Container\n- DI Container는 인터페이스 이름을 키로 사용하여 의존성을 등록하고 해결하는 방식으로 설계되었습니다.\n- 호출하는 쪽에서 구체적인 구현체가 아닌 인터페이스에 의존하기 때문에 모든 컴포넌트는 의존성을 등록할 때 인터페이스 타입으로 컨테이너에 저장해야 합니다. \n- Repository는 싱글톤 패턴처럼 한 번 생성된 인스턴스를 공유하도록 instance로 등록합니다.\n- UseCase는 클로저 기반 팩토리 메서드로 등록하여 호출할 때마다 새로운 인스턴스를 생성합니다.\n- 이러한 방식은 타입 안전성이 좋지 않아서 런타임 오류 가능성이 있습니다. 실제 프로젝트 환경에서는 SwinJect를 사용하거나 위와 같은 문제를 해결해서 사용해야 더 안전할 수 있습니다. \n\n### Coordinator\n- **AppCoordinator - 구현체**\n    - 앱의 진입점에서 최상위 네비게이션 흐름을 관리하는 Coordinator입니다.\n    - RootCoordinator 인스턴스들의 생명주기를 관리합니다.\n    - 로그인, 로그아웃시 화면 전환을 관리합니다.\n- **RootCoordinator - 인터페이스**\n    - BaseCoordinator를 확장하여 앱 수준의 화면 흐름을 시작할 수 있는 최상위 Coordinator 프로토콜입니다.\n    - 전체 앱 윈도우를 초기화하고 루트 화면을 설정할 수 있는 권한이 있습니다.\n    - RootFinishDelegate를 통해 AppCoordinator로 종료를 알려줍니다.\n- **BaseCoordinator - 인터페이스**\n    - 각 코디네이터는 자신의 내비게이션 스택을 가지며 관리합니다\n    - childCoordinators 배열을 통해 하위 코디네이터들을 관리하는 구조\n    - viewControllerFactory를 통해 뷰 컨트롤러 생성 및 의존성 주입\n    - finishDelegate를 통해 코디네이터 완료 시 부모에게 알림\n    - attachChild와 detachChild 메서드로 하위 코디네이터 등록 및 해제 간소화\n\n### Network \n- 외부 라이브러리 의존성 없이 자체 구현한 네트워크 계층을 사용합니다. \n- 프로토콜 지향 설계로 유연성을 높였습니다. \n- Stub 모드를 지원하며 네트워크 없이 테스트가 가능합니다. \n- 콜백 기반 방식 대신 Swift Concurrency를 활용한 비동기 네트워킹을 구현했습니다. \n- 주요 컴포넌트\n    - Network Endpoint \n        - 네트워크 요청의 기본 정보를 캡슐화하는 프로토콜\n    - Network Task\n        - 네트워크 요청 데이터 형식을 정의 (Plain, Json, Parameter 등)\n    - Parameter Encoding\n        - URL 또는 JSON 형식으로 매개변수 인코딩 처리\n    - NetworkSession\n        - 실제 네트워크 요청 수행 및 응답 처리 \n    - NetworkLogger\n        - 디버깅을 위한 네트워크 요청/응답 정보 로깅\n    - NetworkError\n        - 발생 가능한 네트워크 관련 오류 열거형으로 정의 \n\n### Storage\n- 추상화된 스토리지 인터페이스\n    - 각 스토리지 계층은 인터페이스로 추상화되어 구현체 교체가 용이합니다.\n    - 의존성 주입을 통해 테스트 시 Mock 구현체 활용이 가능합니다. \n- 토큰 스토리지\n    - 토큰 관리를 위한 핵심 프로토콜이며, 해당 스토리지는 Core 계층에 있습니다.\n- 이미지 캐싱 스토리지\n    - LRU(Least Recently Used)알고리즘 기반으로 구현했으며, Actor 활용으로 동시성 문제를 해결했습니다.\n    - 더블 링크드 리스트와 딕셔너리 조합으로 O(1) 접근 시간을 보장하고 있습니다. \n- 사용자 데이터 스토리지 \n    - 앱이 실행 중일 때만 유지되는 휘발성 스토리지 입니다. \n    \n### Data / Domain \n- 프로토콜 기반 통신\n    - Domain 레이어에 Repository 인터페이스를 정의하고 Data 레이어에서 구현체를 제공\n- Swift Concurrency 활용 \n    - Data 및 Domain 레이어 전반에 걸쳐 async/await 활용 \n- 의존성 주입 \n    - Repository와 UseCase 모두 인터페이스를 통한 의존성 주입 \n    - DIContainer를 통해 인터페이스 타입으로 컴포넌트 등록 및 해결 \n\n### Presentation\n- Combine을 활용한 MVVM 패턴 \n    - 입력과 출력 분리로 테스트 용이성 향상 \n- MainActor 활용으로 UI 업데이트 관련 메인 스레드 안정성 보장 \n- Coordinator 패턴 활용\n\n## 기술 스택 및 라이브러리 \n- 비동기 처리: SwiftConcurrency (Data \u0026 Domain)\n- 데이터 흐름 관리: Combine (Presentation)\n- 사용 패턴: MVVM, Coordinator, DIContainer \n- 네트워크: URLSession\n- 이미지 캐싱: LRU Cache 구현 \n- 모듈 관리: Tuist\n- 테스트: XCTest\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeon0976%2Fios-cleanarchitecture-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeon0976%2Fios-cleanarchitecture-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeon0976%2Fios-cleanarchitecture-sample/lists"}