Authors: Lennart Lenin Olsen, Robert Koszewski and Lazaros Totsas.

The Project

Run Fatty Run is conceived as a product to make the burger crawling a little more “unsettling”.
All of us often want burgers not knowing what the calories, in said burger, will require us to exercise; i.e. a hamburger might require us to walk 5 kilometers.

We came up with the idea to let people select the burger they crave and then present the user with the restaurant’s available – The caveat then is that the restaurants that are displayed is based on the calories the user would burn walking to them, thereby burning the burger before they even get to the restaurant. That way

The process

The prototype has been developed over 3 months and the basis of the idea have not changed much since then, we introduced a HealthKit integration that has yet to be utilized.

UI/-X Issues

As we were pretty unfamiliar with Xcode development environment  initially the experience of using it and developing an IOS application was straightforward. With just a few clicks the result was quite good by only creating some views and assigning to them different components. Although Apple’s IDE was really helpful with that problems quickly start appearing when we tried to change different IOS devices to get a feeling of how they look in different device sizes. Of course we did not expect that each of the components will automatically scale or adjust to different sizes, but we also did not think that it will be so difficult to make an app that is properly visualized in all the IOS devices.

Apple tried to make the UI developers life easier by creating an auto layout functionality which works quite good, but only if yours components are few and kind of placed aligned to each other. On the other hand when you try to create something like our application which is quite mainstream for the market things are completely different. Auto layout does not work and we had to assign for each and one of the components their constraints. We had to follow different kind of tutorials and walkthroughs to completely understand one basic thing that is not clearly mentioned in Apple’s IOS development web page. Every single one component should have four constraints in all four axis, starting from the initial view which is attached to the device screen borders and moving hierarchically. As a result, in the end all the components have  constraints with other components and if you delete one of them definitely you will have to redo many of the constraints, especially of you delete/change a constraint that is high in the hierarchy. An example is shown in the screenshot where we wanted to place the text description horizontally and vertically aligned inside the image of the map. This time two additional constraints were used, height and width so that the text does not have different size in other devices from our development device Iphone SE.

Continuing with UI/UX navigating through the views is again straightforward from Apple with the use of navigation controller which is responsible to control all the navigation. You just select you start view and select Editor->Embed In->Navigation Controller and without doing anything else you can navigate back and forth. In our app though we did not took this approach as we thought about navigation after the creation of the views and in that point the Navigation Controller was not working as it automatically creates the functionality for the developer. As a result it was actually overriding our implementation or messing up with our code and as a result it was creating multiple views when using it or even breaking up the app entirely.

In the end a completely from scratch navigation controller was made where we could control everything, functionality and visualization. It should be mentioned though that in the current swift and xcode version there is a bug with safe area. Safe area is where the status bar of the device is shown and prevents to show any components there in order to properly viewing the status bar. As a result we needed to bypass this bug that Apple is aware of.

Development Patterns

Apple wants and enforces us to use the MVC pattern.

 

 

Apart from that we tried to introduce the repository pattern in order to create a basis for adding external data sources later on, for now we only have local data so they are used as mocks.

The RestaurantTableViewController view has been rewritten a few times, at one point implementing constraints and auto layout programmatically. This made for a lot of confusion inside the code and was therefore removed – later on  we could properly implement it again as there is quite a few strong suits to it.

Changes between views is done with segues, segues are prepared before the segue actually happens. Each change has to prepare the ViewController it moves to – that is “instantiating” the new view controller ie. setting up the restaurant selection for the map view.
This pattern is also present when moving back through the views, as iOS kills of views that no longer have a reference to them, therefore when going back to the previous view it is auto re-instantiated from scratch. Although in our app there is no backwards data transfer it is very important to mention that when moving data backwards with prepareForSegue:sender: function it does not work as previously mentioned by creating a new view as also deleting the previous view. This time it creates a new view without deleting the initial view thus allocating additional memory.

In order to understand better a visual representation is used with the following diagram visualizing the lifecycle of views when transferring backwards data and forwards. From view A we create a new view B1 and for some reason we want to transfer back to view A some data. When going back with :
performSegue(withIdentifier identifier: String,
sender: Any?)

(void)prepareForSegue:(UIStoryboardSegue *)segue  sender:(id)sender;

It creates a new entirely view  A1 without deleting the A. In order to avoid that we need to use protocols. Since though we did not transfer data to previous views we did not implement protocols but unwind segue. An unwind segue gives the option to go back to the previous view without reinstantiate the whole view. By using unwind segue the user can go back to restaurants list and select a new restaurant while already being in map navigation with the selected burger in memory.

We wanted to manage all of our setups on the “initial splash screen” which has been implemented in our AppDelegate – The only thing we control ourselves though is the HealthKit integration which requires us to request user acceptance. We’ll get back to that later.
The alert that informs user that we are using the GPS is one builtin to the framework.

GPS handling

GPS usage in iOS is a quite straightforward, first we request the user the user location and at some point we will get a result, usually straight away because the device holds the lastest seen GPS coordinate.

More interesting though is the guidance system, as stated earlier we need resturants ordered by the distance to them, specifically the walking distance and the walking route – When listing the restaurants we then request the walking distance to each of them;

 

let directions = MKDirections(request: directionRequest)

directions.calculate(completionHandler: {

 response, error in



 guard let response = response else {

 if let error = error {

  print("Could not get proper directions: " + error.localizedDescription)

 }

 return

}

rest.distanceFrom = response.routes[0].distance

self.addResturantToList(restaurant : rest)

})

}

 

Retrieval of directions and path plottingThis is done for every restaurant known to us, which is not ideal. We will get back to the issues this presents

At the beginning we had issues finding the right APIs to retrieve the Directions to plot them on the map, so the first plan was to use the Google Direction API which can be used for free and plot the result to Apple’s MKMapView. The Google Direction API is a JSON API that uses the current coordinates and the destination coordinates as input and returns a JSON array with the directions and a spline used to plot the line the user has to follow. Although shortly after we found the Apple’s MKDirectionsRequest API which allows to do the same directly without any extra libraries. This speeded up directions retrieval greatly. Once a path is retrieved it is plotted to the map and the user can follow it. Although currently we only support one path retrieval, which means that no matter what path the user chooses to go, the plotted line will always be the same one from the beginning and is not updated. We are still searching how to identify when a user has left the path to recalculate the route, so this may be something we can fix in the future.

Healthkit Integration

HealthKit is a built health framework in Apple’s Ecosystem, it stores information about the user throughout the platform – and later on other apps can fetch that data.
In our case we use a helper function that requests the user to allow us to access this data.

The request is done with a callback function that informs whether or not the user accepted our requests to access HealthKit.

The HealthKit usages has, of now, not been implemented – but we have implemented a Healthier repository that provides a function to query the number of steps taken between yesterday and today. The result is once again provided by a callback.

The Product

Our product is pretty simple and straightforward to understand how it works as it is just a proof of concept. It uses GPS sensor to navigate the user to the selected restaurant to buy and enjoy the selected craved burger. When the user first installs the application two screens appear that request for permissions to use the GPS sensors and give permissions to the HealthKit to use various sensors, although as of now the app does not use any functionality from the HealthKit as it is just for proof of concept and future work/implementations.

 

Restaurant Matching Algorithm

The restaurants are based on known danish McDonalds´, they are added the same way they are listed on Wikipedia, this means that they can never be sorted by distance let alone the distance from the user.

The way we solved this problem is with a few different tricks. But first things first, Apples API’s does not let us allow querying more than 10 walking directions at a time, meaning that we cannot just lookup restaurant pr. walking distance.

Step 1 ; Get the restaurants

Restaurants as stated are just copies of wikipedia and hardcoded into the application. Each restaurant is accompanied by a set of coordinates in a CLLocation tuple, this is used to locate the restaurant later on.

We would like that the restaurants came from a web service so that we or someone else could manage them, also Apples own APIs can provide interfaces for this.

Step 2 ; Order the restaurants by distance

When we start up the app we know a user location, this we can use when getting the restaurants.

Basically we loop over all restaurants and add a property to them that identifies the distance to them,

for rest in resturants {
 rest.distanceFrom = currentLocation.distance(from: rest.location)
}

After the, note; euclidian, distance have been added to each restaurant we can then start to order them by the distance, this is done with a nifty function built in to swift called sorted.

After that we return all the restaurants within a given threshold which is calculated from the calories and the expected distances.

Of course euclidean distances don’t work, when given a task of walking, that why we introduced the threshold to limit the number of restaurants but also return ones that are within reason, ie not returning a restaurant in Copenhagen when in Odense.

Lastly we return the restaurants as is and then we use a MapKit MKDirections lookup to “validate” restaurants.

An example of how this works ;

 

The 3 pictures above shows how selecting the hamburger, the lighter bruger presents us with 4 different restaurants in Odense, take note that Hjallese is the listed on top, making it the closest that fits within the “Calorie Burn Limit” The next 3 pictures shows us the scenario if we select a heavier bruger, now Hjallese is not within our “Calorie Burn Limit”.

 

RunFattyRun Functionality

After giving permissions to use the sensors the first screen of the app lands. On the first screen apart from some nice animations to make it more eye-pleasing the user can select a burger from the list of the available ones. While scrolling the list in the header of the view, the images of the burger, the calories as also the description of each one of them changes dynamically. After selecting the burger by clicking the button “FIND MY BURGER” the app shows a list of the hardcoded restaurants that have the selected burger sorted by kilometers/calories. In this view is where the user is first seeing the navigation bar where gives the option to go back and select a different burger. Continuing with the second screen by selecting a restaurant will automatically open the map to catch the burger. The navigation will help navigate the user to the selected restaurant to grab the burger. For now the navigation is hardcoded as the destination restaurant location is static. Future work/implementation where the list of restaurants and burgers are fetched from an online database will give the correct selected restaurant location.

Video Demonstration

https://www.youtube.com/watch?v=hipx5SZdWz0

Future Work

As the project is in a very basic form the possible functionalities that could be implemented are only limited by our personal idea how this project could end up. Some of the most appropriate in short term future implementations are mentioned below based on the MVC. MVC is a development pattern that separates the project for easier handling of three core functions

Model : The current implementation of our models is in a static form with hard coded lists of burgers and restaurants. Extending the models as future work will include getting the list of the restaurants and burgers from an online API and as an extension probably  caching them for faster fetch or offline use.

View : As the application is in prototype form it is supported by three basic views. Further implementations would incorporate the core functionality with user preferences on a settings view as also history view.

Controller : The controllers will be used to support the above new functionality. A controller to handle the probably rest based API calls, saving data to the device and viewing them to history view and the functionality for the user based settings.

Future Work

Source Code: https://bitbucket.org/iosprogrammingsdu/runfattyrun

Acknowledgments

A huge appreciation to Jacob Nielsen for his welcoming approach of the course as also the knowledge and help provided through the entire semester

Leave a Reply