Business Logic

Core Data

In order to be able to save and access the tasks we had to use a database. The recommended way on iOS is to use core data. Core data is an abstraction layer from Apple which can work with objects (it's also called object graph). It abstracts the database so the data in the database can be used as objects from the business logic layer. Typically, it uses SQLite as a database implementation but it can be changed to different kinds of underlying databases.

 

As a starting point we used this (http://www.raywenderlich.com/115695/getting-started-with-core-data-tutorial) blog post. After programming the example and then implementing it in our App however, we decided that it’s a little bit complicated to write all the code all the time, necessary to handle objects. So we wrote a helper class with some easy to use methods. For example to get all the tasks from the database it was necessary to write all this code: 

 

        let predicate = NSPredicate(format: "SELF = %@", repeatable)

        

        let fetchRequest = NSFetchRequest(entityName: REPEATABLE_ENTITY_NAME)

        fetchRequest.predicate = predicate

        do {

            let fetchedEntities = try context.executeFetchRequest(fetchRequest) as! [Repeatable]

            if let repeatable = fetchedEntities.first {

                return repeatable

            }

        } catch {

            // Do something in response to error condition

        }

   

Now after having implemented the helper class, it’s just one method call:

 

         Database.getAllRepeatables(context)

 

Of course we also implemented methods to get the database context, get a new task, get a single task by id or delete a task. The same goes for the locations. 

 

Date calculation

Dates in swift are unfortunately still the same as they were in objective-C. Unfortunately because it’s still kind of complicated. They should have done something like C# were date handling is a blast. 

So because we need countdowns and time differences between dates in different units, we decided to write a helper class like we did for the database. The basics we got from blog posts on the website http://www.globalnerdy.com/2015/01/26/how-to-work-with-dates-and-times-in-swift-part-one/ and http://www.globalnerdy.com/2015/01/29/how-to-work-with-dates-and-times-in-swift-part-two-calculations-with-dates/. 

So for example the method for the time difference between now and a date looks like this: 

 

    // Returns the difference with days, hours, minutes and seconds

    static func diffToNow(date: NSDate) ->  NSDateComponents {

        let userCalendar = NSCalendar.currentCalendar()

        let dayCalendarUnit: NSCalendarUnit = [.Day, .Hour, .Minute, .Second]

        let dateToNowDifference = userCalendar.components(

            dayCalendarUnit,

            fromDate: NSDate(),

            toDate: date,

            options: [])

        

        return dateToNowDifference

    }

 

The problem is that the units which are returned in the object have to be defined up front. So in this example only the days, hours, minutes, and seconds are returned. If one would like to access the years it would fail. In Order to get the years as well, the NSCalenderUnit array would need to look like this: 

 

      let dayCalendarUnit: NSCalendarUnit = [.Year, .Day, .Hour, .Minute, .Second]

 

Another problem was, that we cannot save NSDateComponents in core data. It is only possible to save NSDate as datatype. Because we need to save the timespan how long a countdown should be running, we decided to just convert it to seconds and save it as Integer. But when calculating the dates and new countdowns we convert it back to NSCalendarUnits, because it’s easier to handle. 

 

iOS MapKit

MapKit is an iOS-API, that is used to display maps, jump to coordinates, plot locations and draw routes and shapes on a map. In our case we need to integrate a MKMapView as a base view for realizing the Map Screen. Furthermore we have to tell the MapKit the users location to obtain a map which shows his location. But for the use of such sensitive data, of course, user-permissions are required. 

 

First we had to create a MapViewController and import the MapKit framework at the top of the file as shown below. After the creation of a MapView- and a LocationManager variable (to obtain the user location), the viewDidLoad method had to be changed. This method is called when the view is loaded into memory. Due to this method is executed only once during the life cycle of a view controller object, it is a suitable place for setup methods and view initialization. 

 

Here we adapted the configuration of the CLLLocationManager object instance to use the 

“best accuracy” setting to obtain the user location as accurate as possible. We also declared the view controller instance as the application delegate for the location manager and the map view object. Delegation is a design pattern in Swift that enables a class to delegate some of its responsibilities to an instance. A delegation is mostly used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source (Explanation of the iOS Developer Library). 

 

       import MapKit

 

       class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

 

           private var mapView = MKMapView()

           private var locationManager: CLLocationManager()

 

                override func viewDidLoad() {

                super.viewDidLoad()

 

               locationManager.delegate = self

               locationManager.desiredAccuracy = kCLLocationAccuracyBest

               locationManager.startUpdatingLocation()

               locationManager.requestAlwaysAuthorization()

        

               mapView.mapType = .Standard

               mapView.frame = view.frame

               mapView.delegate = self

        

               view.addSubview(mapView)

       }

 

Project properties can be saved in a plist-file. For the location permissions we first implemented „NSLocationWhenInUsageDescription“ in the plist and also made a call to locationManager.requestWhenInUseAuthorization() to ask the user for the permission to track location information. But than we realized that this permission just allows us to track the location information while the application is in the foreground. But later we also need the opportunity for sending Push Notifications that notifies the user when he is in a certain area of a given task. For this we needed a stronger permission and implemented „NSLocationAlwaysUsageDescription“ in the plist. With the call of locationManager.requestAlwaysAuthorization(), the user will now be asked for a permission that allows Repeat to access his location even when he is not using this app.

 

The call of the startUpdatingLocation method ensures that the locationManager will be updated every few seconds about the current user location which is seen below.

 

       func locationManager(locationManager: CLLocationManager, didUpdateLocations locations: [CLLocation]){

               if let loc = self.mapView.userLocation.location {

                   let region = MKCoordinateRegionMakeWithDistance(

                       loc.coordinate, 500, 500)

                  self.mapView.setRegion(region, animated: true)

               }

        }

Rate this blog entry:
0
Start to Implement
Network architecture

Related Posts

 

Comments

No comments made yet. Be the first to submit a comment
Already Registered? Login Here
Guest
Saturday, 19 August 2017

Captcha Image