An simple recipe finder iOS app built using MVVM pattern, clean code, and unit testing coverage and best practices used in modern iOS programming using Swift
.
- Showing a list of great recipes from a source
- Showing them in grid layout in landscape mode
- On device orientation change, show a different view with more detail of the recipe but within same container
- Used same collection view cell dynamically using size class to detect device rotation to support both layout
- Used
UICollectionViewCompositionalLayout
in iOS13+ - Used
Combine
for reactive binding - Load images of the recipes separately and cache them and fetch the data incrementally as user scrolls though to manage network bandwidth better
The data for the recipes stays in local JSON
file. But it can be loaded from a remote source url using http GET
if needed. Full support for network layer has been added with potential custom error handling. See usage in view model on error outcome in loading.
At this stage the app points to the local JSON data source. See tech note of the ApplicationComponentsFactory
and how dependency injection works there.
/// TODO: Here is the glue. Use `defaultProvider` when real network loading is needed
/// For now leaded locally from a JSON file
networkService: ServicesProvider.localStubbedProvider().network
- See view model logic of error handling & empty state handling
Placeholder
view is created to achciev these two cases using same view
Quick
- To unit test as much as possible 🤫Nimble
- To pair with Quick 👬
Combine
– To do reactive binding when needed 🤫UIKit
– To build as usual everywhere 😀
ViewController
talks toViewModel
which relies onUseCase
under its layer- The
ViewModel
processes lower level domain models of recipes and converts into higher levelRecipeViewModel
items for the need of the UI ViewModel
take helps fromTransformer
- Accessbility ID, label, hints, traits etc calculation and any other formatting etc. is done via the
Transformer
ViewModel
andTransformer
are individually unit tested- There is some support for
Routing
to show how it can be achieved throughFlowCoordinator
pattern - Some glue code left with some tech notes how the recipe cell tapping and detail view navigation can be done in future
ApplicationComponentsFactory
helps in DI and pick the service injection that is need- Other layers of the app in domain and data level everything is
protocol
driven to achieve loose coupling and DI based unit testing. - See unit tests at each layer
Folder / Grouping are done as per below: Project has 2 targets:
- RecipeBoss - The main code
- RecipeBossTest - Unit testing of all layers using Quick/Nimble
Codebase has 3 layers:
- PresentationLayer
- DomainLayer
- DataLayer
- Custom accessibility to each element is supported
- Accessibility identifiers are injected to each element to help support
UI Automation Testing
- See Transformer logic to see acessibility computations
TODO
more work is needed after supporting paginated carousel support. Perhaps full cell should be one accessibility element with some children inside as well.
- Coming up next ...
- All colours can be used from a central Theme provider helper that would support dynamic colour switching
- Custom font can also used
- See some usage in my other repos [here] (https://github.com/arinjoy/MyBank/blob/master/MyBank/PresentationLayer/Shared/Theme/Theme.swift)