Sytac iOS assignment | Movies
The time has come for us to unveil the code challenge Sytac has prepared for you. The challenge involves working with the Movies application and includes the following tasks:
Questions
- Provide a high-level review of the application. Give your opinion on both aspects you consider positive and aspects you consider negative. Describe how and why would you do things differently.
- The logic of ImageCache hides an issue. Try to discover and fix it.
- Replace the binding between Repository and View model without combine.
- Replace the Popular detail view with a new custom detail view. This view should display a detail with the info of the model movie model. Please use SwiftUI for the detailed view.
- Replace the TopRated tab with a new list view. This view should display a list of the TopRated movies and it must be implemented programmatically using UIKit.
- Write unit tests whereever you need them.
- In MoviewRow.swift line 11 we use @StateObject, could we change it with @ObservableObject? what are the differences?
- In PopularMoviesListViewModel.swift we ask for popular movies, using the current implementation fetch top rated movies instead, and explain what is happening.
- Implement load more functionality for Popular movies list screen.
You have total freedom to modify the codebase, there are no constraints on the design/layout of the TopRated screen. The TopRated List and detail view should be created programmatically only (no Interface Builder nor SwiftUI).
Notes: The Movies project works with Xcode 12 and up and the language used is Swift.
Backend:
To retrieve movies related data, the application is using this API https://www.themoviedb.org/documentation/api
Requisites:
- The project has to compile without errors.
- The code should be clean, efficient and understandable. Remember to structure your source code correctly (using a nice architecture would make this easier).
- Keep in mind the performance of the application.
- Use version control in the project to show your progress, commit like you would normally.
- We would like to see at least the first 5 questions solved, the more you provide the better.
Good luck!
License
MIT Free Software!
Paulo's Test
Architecture
The app uses MVVM architecture to define its separation of concerns. SwiftUI and Combine are used to bind UI elements and interactions in the popular tab. In overall classes are small and encapsulated, which make the app scalable. For dependency management, Swift Package Manager is the tool of choice.
As for suggestions:
- Include a new protocol for
viewModel
that will defineInput
andOutput
objects, which make communication betweenview
andviewModel
clearer. - Change the way
view
communicates withviewModel
, for example line32
onMoviewRow
,.onAppear(perform: { movie.fetchImage() })
. Aview
should not initialize a function insideviewModel
but instead inform that an action was performed, e.g:.onAppear(perform: { movie.input.onAppear() })
. In the future if aviewModel
needs to be updated or add more functionalities to a specific action, the view does not need to change, instead just reflect theviewModel
state. - Some classes have difficult or unclear naming, e.g:
MovieAdaptor
,PopularMovie
; Unless you open the class and read it, you won’t know what they do so I would suggest adding a few prefixes/suffixes to these filesPopularMovieAdapter
PopularMovieViewModel` - Folder structure could be improved by adding a few layers for each feature, e.g:
View/Popular/Row
; Bundlingmodel
,viewModel
andview
in the same folder for a specific feature.
ImageCache Logic
Problem:
Images not loading when multiple requests are from the same URL
How to reproduce:
Add in line 32 this code let newUrl = NSURL(string: "https://image.tmdb.org/t/p/w500/jKuDyqx7jrjiR9cDzB5pxzhJAdv.jpg”)!
Replace all url
variable uses to newUrl
, no images will load until you scroll the tableView and cells start requesting from cache instead of needing download.
Fix 1 (Not good but quick): Line 42 and 67 have a return
to stop the function. Line 42 avoids same url requests to be executed in succession. Line 67 avoids blocks of the same url
to be called, preventing updates to UI.
Commenting both lines, will provide a quick fix to give us time for a proper investigation if issue is critical and needs redeployment. But it may cost more bandwidth and phone memory by updating the views many times.
Fix 2 (Better):
- Add more control flows to NSCache with
lock
- Make use of Quality of Service =
Utility
on ourNSThread
to provide a better performance. - Perhaps use Core Data to provide a longer term Cache for users
Replace binding Repository and View model without combine
I’ve added a class called Binder
which uses a technique called Boxing
, making it easy to drop in and does not require complex changes to the project such as adding RxSwift.
Replace Popular Detail
I’ve added a new design for the detail page, including more data then the popular list.
Replace TopRated Tab
I’ve added a new design for the list page, using entirely UIKit.
Unit Tests
No tests added
MovieRow @StateObject vs @ObservableObject
Yes, in this case it is possible to change @StateObject
to @ObservableObject
. The main reason is that MoviewRow does not own the instance of PopularMovie
and needs to only observe the object. A good class to understand their differences are in this class from WWDC: https://developer.apple.com/videos/play/wwdc2020/10040/
Fetch Top Rated
To enable Top Rated fetching, we can switch line 25 of PopularMoviesListViewModel.swift
from moviesRepo.getPopular()
to moviesRepo.getTopRated()
. This function will instantiate TopRatedMoviesService
instead of PopularMoviesService
, this means we will call a different API, on a different path compared to PopularMoviesService
, resulting in a a different service response, in this case, IMDB’s Top Rated
movies.
Load More for popular movies
Not provided.