# SearchApp
<img src="https://i.imgur.com/nAWiHP2.png" alt="search-light" width="375"/>
[웹페이지](https://hackmd.io/@3TnIQNtHScaiPOUgeaRJtg/HkAxNGZgc)에서 보려면 링크로 이동하세요.
## 프로젝트 소개
[Itunes Search API](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/iTuneSearchAPI/index.html#//apple_ref/doc/uid/TP40017632-CH3-SW1)를 통해 앱스토어의 앱 정보를 제공하는 애플리케이션을 제작합니다.
- 메인화면의 검색창을 이용해 원하는 앱을 검색 할 수 있습니다.
- 검색창이 비어있는 경우 **최근 검색어 목록**이 표시됩니다.
- 검색창에 텍스트를 입력하면, **추천 검색어 목록**을 표시합니다.
- 검색 버튼을 탭하여 **앱 목록**을 확인 할 수 있습니다.
- 최근, 추천 검색어를 탭하여 앱 목록을 확인 할 수 있습니다.
- 메인 화면의 앱목록에서는 **앱아이콘**과 **이름**, 회사이름, **평점**, 3장의 **스크린샷**을 표시합니다.
- 목록에서 앱을 선택하면 추가적으로 **새로운 기능**, 버전과 **여러장의 스크린샷**을 표시합니다.
- 상세 화면에서는 여러줄의 **앱이름**과 회사이름을 표시합니다.
- 새로운 기능이 3줄 이상인 경우 **더보기** 버튼을 통해 확장 기능을 제공합니다.
- 스크린샷을 **가로로 스크롤하는 기능**을 제공합니다.
## 주요기능 미리보기
| <img src="https://i.imgur.com/gxCz4cq.gif" alt="search-light" width="375"/> | <img src="https://i.imgur.com/qeJm4sr.gif" alt="search-dark" width="375"/> |
| - | - |
## Tools
### 개발환경 및 타겟 OS
- Swift 5.7
- Xcode 14.2
- iOS 13.0
## 설치
프로젝트에 꼭 필요한 설치 파일([SwiftLint](https://github.com/realm/SwiftLint), [SwiftFormat](https://github.com/nicklockwood/SwiftFormat), [SwiftGen]([SwiftGen](https://github.com/SwiftGen/SwiftGen))) 및 git config 설정
- `sh setup.sh`
## 기술
| 구분 | 기술 |
| -- | -- |
| 의존성 관리 도구 | [Swift Package Manager](https://github.com/apple/swift-package-manager) |
| 아키텍처 프레임워크 | [RIBs](https://github.com/uber/RIBs) / [ReactorKit](https://github.com/ReactorKit/ReactorKit) |
| Reactive Programming | [RxSwift](https://github.com/ReactiveX/RxSwift) / [RxCocoa](https://github.com/ReactiveX/RxSwift/tree/main/RxCocoa) |
| UI | [UIKit](https://developer.apple.com/documentation/uikit) / [SnapKit](https://github.com/SnapKit/SnapKit.git) |
| 네트워크 (HTTP) | [Alamofire](https://github.com/Alamofire/Alamofire.git) |
| 내부저장소 (Persistance) | [Stores](https://github.com/omaralbeik/Stores) |
| Image Fetching / Caching | [KingFisher](https://github.com/onevcat/Kingfisher) |
| 테스트 | [RxTest](https://github.com/ReactiveX/RxSwift/blob/main/Documentation/UnitTests.md) |
## 코딩 컨벤션
[스타일가이드](https://github.com/topkim993/swift-style-guide)에 따라 작성하며, [SwiftLint](https://github.com/realm/SwiftLint)와 [SwiftFormat](https://github.com/nicklockwood/SwiftFormat)으로 도움을 받습니다.
## 패키지 구조
### Feature Packages (CX, ...)
`Clean architecture`에 착안하여 `Repository`, `Domain(UseCase, DomainEntity)`, `Presentation` Layer로 나누었습니다. 각 레이어의 역할은 아래와 같습니다.
| 구분 | 역할 |
| --- | --- |
| Repository | DataSource에 데이터 제공을 요청하는 역할을 수행합니다. 이 과정에서 데이터의 출처를 추상화합니다. |
| UseCase | 앱의 핵심 비즈니스 로직을 수행합니다. 목적 사용 케이스에 따라 비즈니스 로직이 분리되어 있습니다. 이 과정에서 Repository를 통해 전달받은 데이터를 앱이 제공하는 핵심 비즈니스 로직에서 활용하는 엔티티 형태로 변환합니다. |
| DomainEntity | 비즈니스 로직에서 활용하는 엔티티 입니다. |
| Presentation | Domain 레이어에서 목적에 맞게 가공된 데이터를 제공받아 화면에 표시하는 역할을 수행합니다. 화면에 최종적으로 보여줄 내용을 가공하기 위해 상태와 액션, 의존하는 환경을 정의하여 사용하며, 사용자와의 상호작용, 데이터 변화 등의 이벤트를 단방향의 Redux 패턴으로 수행합니다. |
### DataSource
네트워크 또는 내부저장소에서의 데이터 제공을 담당합니다.
| 구분 | 역할 |
| --- | --- |
| HTTPAPI | HTTP 네트워크 통신 API를 정의 합니다. |
| LocalStoreAPI | 내부저장소 관리 API를 정의 합니다. |
### Platform
네트워크 모듈과 유틸리티들이 존재 합니다. 해당 프로젝트 뿐만 아니라 다른 프로젝트에서도 사용 할 수 있도록 구성합니다.
### UserInterface
UI 구성에 필요한 리소스 관리를 담당합니다.
### Constant
프로젝트에 필요한 상수 관리를 담당합니다.
## RIB Tree
<img src="https://i.imgur.com/Y0xF3Vx.png" alt="rib-tree" width="300"/>
## Presentation 상세
- 한개의 `Scene`을 담당하는 `RIB`을 `Viewable`의 경우 `View`를 따로 분리하여 2개로 모듈화 되었습니다.
- `RIBs`의 `Interactor`와 `ViewController` 관계를 구조화 하기 위해 `ReactorKit`으로 구성 되었습니다.
- `ViewController`는 프로토콜을 통해 `Reactor`를 알 수 없도록 구성 되었습니다.
- `ReactorKit`의 `State` 외 추가적으로 `ViewState`라는 상태를 만들어, `ViewController`의 역할을 줄였습니다. 예를 들어 `ViewController`는 `Date Formatting` 또는 `Int` -> `String` 캐스팅 같은 행위를 하지 않습니다.
## 개선할 수 있는 점
~~- Search RIB의 경우, 최근검색어, 추천검색어, 결과목록의 3가지의 기능으로 분리 되지만 하나의 RIB에서 처리 되고 있습니다.분리하여 조금 더 작은 RIB 단위로 나눌 수 있을 것 같습니다.~~
급하게 `RIB`을 분리하면서 `Search RIB`의 구조가 변경 되었습니다.
`Interactor`의` Action`을 `ViewController`부터 받은 `Action`과 `Child RIB Listener`를 통해 받은 `Action`을 구별 하였습니다.
`Search`의 하위 `RIB`(`RecentSearches`, `SearchedApps`, `SuggestedSearches`)과 `Detail RIB` 구조를 통일하지 못했는데, 모두 같은 구조로 가져가면 좀 더 읽기 쉬운 코드가 될 것 같습니다.
같은 이유로 `Search RIB`의 경우 테스트가 깨져서 테스트코드가 동작하지 않습니다.
혹시, 테스트코드 확인이 필요하시면 `SearchApp-Old`를 확인 부탁 드립니다.