This repository is a modular implementation of a movie search application using the VIPER architecture. Below are the details of the code organization, its usage, and how to set it up.
The project is organized into the following key modules and components:
This module handles displaying and searching for movies.
- Builder: Handles the creation and wiring of the Movie List module.
- Interactor: Fetches data from the repository.
- Presenter: Coordinates between the view and the interactor.
- View: Displays data to the user and handles user input.
- Router: Manages navigation to other screens.
This module handles displaying the details of a selected movie.
- Similar structure as the Movie List Module.
The project uses a DependencyContainer
for managing dependencies across the application. It supports singleton
and transient
lifetimes.
Helper utilities include:
- Extensions: Convenience methods for
UIView
,UITableView
, etc. - Design Kit: Centralized styling constants like padding and fonts.
- Loading View: A reusable loading indicator.
- Error Handling: Utilities for displaying error alerts.
The project uses SUNetworking
for network requests and response handling. This layer is abstracted into the DataService
and Repository
.
The project leverages UICollectionViewDiffableDataSource
to manage and update the collection view data seamlessly. This ensures smoother UI updates and less boilerplate code for managing sections and rows.
The application supports localization, making it easy to adapt the user interface for multiple languages. All user-facing text is managed through localized strings files. Additionally, LocalizationKey
extensions are used to define strongly-typed keys for localized strings:
Unit and snapshot tests are implemented for key modules:
- Unit Tests: Validate interactor, presenter, and router logic.
- Snapshot Tests: Ensure views render correctly across different configurations.
- Xcode 15 or later
- Swift 5.5 or later
- Clone the repository:
git clone https://github.com/snnlsy/OMDB-VIPER.git cd OMDB
- Open the project in Xcode:
open OMDB.xcodeproj
- Build the project:
- Select a simulator (e.g., iPhone 14 Pro).
- Press
Cmd + B
to build.
Run tests using Xcode:
Cmd + U
to execute all tests.- Snapshot tests require a simulator to generate or compare snapshots.
- Launch the app.
- Use the search bar to enter a movie title or keyword.
- Results appear in both table view and collection view layouts.
- Tap on a movie in the table or collection view.
- The app navigates to the detail screen displaying the movie's title, year, and poster.
This project follows the VIPER design pattern, which provides clear separation of concerns:
- View: Displays data and captures user input.
- Interactor: Business logic and data handling.
- Presenter: Mediator between view and interactor.
- Entity: Data model.
- Router: Navigation and module initialization.
DependencyContainer
allows for easy management of dependencies:
DependencyContainer.shared.register(NetworkServicing.self, lifetime: .singleton) {
NetworkService()
}
The application supports multiple languages through the use of localized string files. This ensures a seamless user experience for users across different regions. Strongly-typed keys defined in LocalizationKey
extensions are used for better type safety and maintainability:
extension LocalizationKey {
static let movieListTitle: LocalizationKey = "movieList.title"
}
Error alerts are standardized:
router.showError(description: "Network Error") {
// Retry logic
}
Mock classes and expectations validate behavior:
func test_retrieveMovieList_informsOutputOnSuccess() {
let expectation = XCTestExpectation(description: "Output should be informed with success response")
output.didRetrieveMovieListExpectation = expectation
repository.response = .success(expectedResponse)
sut.retrieveMovieList(query: "TestQuery", page: 1, movieListType: .tableView)
wait(for: [expectation], timeout: 0.5)
}
- Transition from callback-based patterns to async/await for cleaner and more modern concurrency handling.
- Implement consistent error handling across modules with user-friendly messages and robust logging mechanisms.
- Replace the Timer-based search bar debounce logic with a Combine or Swift concurrency-based implementation.