검색키워드를 입력하면 서버 데이터를 전달받아 목록 화면에 나타냅니다. #1
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
📚 배경
📚 작업 내용
URLSession
을 통해 네트워크 통신을 구현했습니다. (MockURLSession을 통한 테스트 실행)SearchController
를 통해 사용자가 검색어 (책 제목, 저자, 출간연도 등)를 입력합니다.Label
에 나타내고, 검색된 도서는CollectionView
에 나타냅니다.Pagination
을 구현했습니다.ActivityIndicator
를 통해 로딩 애니메이션을 보여줍니다.Cache
를 구현했습니다.1. 네트워크 구현 및 API 추상화
RxSwift
를 활용하여 비동기 작업을 처리했습니다. 서버에서 받아온 데이터는Observable
타입으로 반환하고, ViewModel에서 ViewController에 전달 (Binding)하여 화면에 나타내도록 구현했습니다. 이때 데이터를 화면에 나타내는 최말단 시점에만Subscribe
하여 Stream이 끊기지 않는 구조를 유지했습니다.또한 API를
열거형
으로 관리하는 경우, API를 추가할 때마다 새로운 case를 생성하여 열거형이 비대해지고, 열거형 관련 switch문을 매번 수정해야 하는 번거로움이 있었습니다. 따라서 API마다 독립적인구조체
타입으로 관리되도록 변경하고, URL 프로퍼티 외에도HttpMethod
프로퍼티를 추가한 APIProtocol 타입을 채택하도록 개선했습니다. 이로써 코드유지 보수가 용이하며, 협업 시 각자 담당한 API 구조체 타입만 관리하면 되기 때문에 충돌을 방지할 수 있습니다.2. MVVM-C 적용
Coordinator
를 통해 의존성 주입을 관리하고, 화면전환 역할을 전담하도록 했습니다. 이를 위해navigationController
를생성자 주입
으로 하위 ChildCoordinator에 전달하고, 화면전환 시 해당navigationController
가 다음 화면을 push 하도록 했습니다.3. DiffableDataSource 및 Snapshot 활용
사용자가 검색 키워드를 입력할 때마다 목록을 업데이트하도록 구현하기 위해
DiffableDataSource
를 활용했습니다.reloadData()
를 호출할 필요가 없으므로 CollectionView Cell이 업데이트될 때마다 애니메이션이 적용되어 UX 측면에서 유리하다고 판단했습니다.또한 RxSwift를 통해 ViewModel과 ViewController를 Binding 시켜 역할을 분리했습니다. 예를 들어 사용자가 목록화면에서 스크롤을 최하단으로 내리면,
ViewModel
은 서버를 통해 데이터를 업데이트하고,ViewController
는 Snapshot을 apply하여 화면을 다시 그리도록 했습니다.4. Compositional Layout 활용
CompositionalLayout
을 활용하여 Item/Group/Section 요소를 반응성 있게 배열했습니다. 또한 높이는estimatedHeight
, 너비는fractionalWidth
를 활용하여 Cell의 크기가 Device에 따라 유동적으로 조절됩니다. 특히estimatedHeight
를 사용하여 Cell의 높이를 고정하지 않고, Cell의 내부 구성에 따라 자동으로 산정하도록 했습니다.5. SearchController를 통한 검색창 구현
UISearchController를 활용하여 NavigationBar 내부에 검색창이 위치하도록 했습니다.
SearchBar
대신UISearchController
을 사용한 이유는 목록을 Scroll할 때 자동으로 검색창을 숨기고, 검색창에 텍스트를 입력할 때 자동으로 Navigation Title을 숨기는 등 사용자에게 보다 직관적인 UX를 구현할 수 있기 때문입니다.6. 이미지 Cache 구현
UIImageView
익스텐션으로메모리 Cache
가 있으면 해당 이미지를 가져오고, 없으면 imageURL을 통해 받아오도록 했습니다. 이때ImageCacheManager
를 추가하여Notification
을 통해 메모리가 부족하면 Cache를 삭제하도록 했습니다.📚 테스트 방법
JSONParserTests
에서 Mock 데이터 (MockSearchResult, MockBookItem)을 활용하여 Parsing이 정상작동하는지 테스트했습니다.MockNetworkProviderTests
에서 네트워크 관련 기능이 정상작동하는지 테스트했습니다. MockURLSession을 통해 실제 서버의 영향을 받지 않는 독립적인 테스트가 가능합니다.NetworkProviderTests
에서 실제 서버 데이터가 정상적으로 전달되는지 테스트했습니다.📚 리뷰 노트
📚 스크린샷