This application is using the MVVM design pattern to render views using view models responsible for holding the state of those views. This helps with not running into the MVC ("Massive View Controller") problem as the view controller and the view have less responsbility taking advantage of the seperation of concern principle. Dependency injections are used to ensure an entity is given the correct input during the creation. This is evident in the creation of the Singleton WorkoutData class. Since the data being displayed is coming from one source of truth (the data file), it made sense to treat the WorkoutData class as a Singleton ensuring more than 1 is not created (we don't want to read more than 1 file at a time). We use a failable initializer to fail immediately if the given file is not found in the project. Extensions are used to separate out logic when conforming to protocols to ensure a Swifty environment. Since this is a simple layout with 2 pages, all of the UI design is done using the main storyboard. A reusable xib for the exercise table view cell is used in the storyboard for the 2 places it appears.
Auto Layout is used to ensure that all the views are situated in the correct manner for all devices. Alerts and loading indicators are used whenever the user needs to be told of something.
Three pods are used extensively in this project:
- CSVImporter - I chose this pod because it was one of the only ones that imported line by line of a CSV file rather than creating a massive String object and then parsing it. This ensures that there will be no memory issues as we are getting a line by line mapped object through Swifty closure callbacks. We make sure to run the actual importing task on the .utility background global queue whereas the closure callbacks are ran on the .userInteractive background global queue. Once the results come in, we delegate to the OneRepMaxViewController which renders the data into the table views on the main queue.
- Charts - I chose this pod due to the immense popularity it has on Github. It is very widely used as it is the iOS clone of the very popular Android version. Charts allowed me to display the historical values of the data on both axis. With a good amount of customization, I was able to get it close as possible to the mocks.
- NVActivityIndicatorView - I chose this pod for the customization it provided for indicators. I really liked how the protocol included can be conformed by a View Controller and transform the View Controller to be of that type to allow UI blocking. I used this initially when the import starts. It is useful in the case where an import of a huge file is happening showing the number of lines we've imported so far.
Instead of using the approximation calculation method, I used the exact calculation method: (w * (36 / (37 - r))). The max rep calculations are all done in Floating point integers and are stored in Floats as well. However, I chose to display the one max rep as Integers (Floats are truncated) in the app to allow for a more appealing experience.
Right now, the data is presented in the table view as soon as all of it has been crunched and stored in the dictionary so in other words, the table view only shows data once the entire data file has been imported. Another approach I had was to enable more of a "real-time" update approach. In this case, as we import new data for a specific exercise, we would update the table view cell. With the same indicator view in the foreground, the table view would continue updating each cell based on the newest accumulated data. Both approaches are sufficient and based on the context and requirements, either can be used. I chose the former due to the time constraint I had on doing this project along with what I think is the better approach for this kind of application. The entire point of this app is to import the data and present it, not necessarily make it a very "interactive" application. The latter approach could potentially have a performance hit as well due to the repetitive updates and animations being run. This will be hightened especially when the CSV file is huge.