• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 4/27/23

Take Advantage of Out-Of-The-Box Solutions

We’ve got new resources available in our project.  Now let’s put them to a good use!

Analyzing the API

Each library is organized differently, providing the functionality that was optimal in the eyes of the authors.

A set of available elements - data types, properties and methods provided by the library are called Application Programming Interface (or API for short).

Charts API

The best way to start orienting ourselves is by looking at the demo to isolate parts that are suitable for our project. We can easily spot a PieChart appearance that looks like the one we have on our mockup:

Identifying needed components
Identifying needed components

At times, documentation of API is available. This is an ideal situation. More often than not, however, you'll need to orient yourself by exploring your options through the code.

If a demo is provided, it's the best place to start. In our example, PieChartViewController.swift file looks like the one responsible for displaying our chart.

Let's first identify what we need to display:

  • Emotion captions, we'll have 5 of them:

    • 3 for each emotion

    • 1 for snoozing

    • 1 for not logged days

  • Number of times emotion is captured within a set period of time.

From the content of that file we can find out the following options that are useful for our implementation:

  • Demo option -  Toggle Y - Values is related to displaying the numbers

  • Demo option - Toggle X - Values is related to displaying the captions

  • The first slider is setting the number of slices - emotions

  • Second slider is setting the proportion of each slice in relation to the whole.

Looking at the code we can identify that:

  • The data is supplied in a form of an array with  PieChartDataEntry  class elements.

  • The chart it provided by  PieChartView  class.

Now let's explore those further in our Analytics View Controller.

Implementing the Charts for Amazing!

Build the interface

We'll start by building the UI.  Let's switch to the storyboard and add the following elements to the new screen:

  • Label - to hold the title

  • Segment Control - to provide for time period selection

  • View - to serve as a base for the PieChart

Then select the View and assign PieChartView class to it on Identity Inspector:

Amazing Analytics UI!
Amazing Analytics UI!

Connect UI to the controller

Next, as usual, we need to connect the UI elements we've just added to the view controller code - AnalyticsViewController.swift. We are only going to need the segment control and pie chart:

IBOutlet weak var pieChartView: PieChartView!
@IBOutlet weak var timeSegment: UISegmentedControl!

Let's now capture the segment control value change. For that we need to create an action for ValueChanged event:

Creating an action for Segment Control ValueChanged event
Creating an action for Segment Control ValueChanged event

And name the action method timeSegmentValueChanged

@IBAction func timeSegmentValueChanged(_ sender: Any) {
}

And let's prepare a couple of helper functions - a usual view controller configuration and the other one to set data. Then call both of them within viewDidLoad method and set data in timeSegmentValueChanged:

@IBAction func timeSegmentValueChanged(_ sender: Any) {
setData()
}
func configure() {
let legend = pieChartView.legend
legend.horizontalAlignment = .right
legend.verticalAlignment = .top
legend.orientation = .vertical
}
func setData() {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
configure()
setData()
}

Prepare the data

Fetch data from the database - add functions to DataController

Convert into an array of piechartentries

Configure PieChart

Here we need to accomplish a few things:

  • Make sure we've got the legend to appear in the right top corner.

  • Provide an array of data elements corresponding to the pie slices. 

  • Provide text for central label and for chart description.

To configure a legend, we need to set a number of properties we can find in the demo. We'll place them in our helper confirmation method:

func configure() {
let legend = pieChartView.legend
legend.horizontalAlignment = .right
legend.verticalAlignment = .top
legend.orientation = .vertical
}

Next we need to provide an array of data points for the pie slices. So far the data controller functionality implements a method that fetches a set of logs, but what we need is a count of each emotion for select period of time. Let's go ahead and add a method for it to the data controller:

func count(logs: [NSManagedObject], emotion: Emotion) -> Int {
return logs.filter {(log) -> Bool in
return (log as! Mood).emotion == emotion.rawValue
}.count
}

In this implementation we are simply filtering an array of logs by a single emotion and returning the result count.

Let's make the data controller accessible within analytics view controller. For that, we need to import the CoreData framework:

import CoreData

Declare a DataController variable:

let dataController = DataController()

This makes us ready for setData method implementation:

func setData() {
var logs: [NSManagedObject]
if timeSegment.selectedSegmentIndex == 0 {
var date = dataController.today
date.addTimeInterval(-Double(30 * 3600 * 24))
logs = dataController.logs(from: date, to: nil)
}
else {
logs = dataController.logs(from: nil, to: nil)
}
var entries = [
PieChartDataEntry(value: 0, label: "No data")
]
var centerText = ""
var chartDescription = ""
if let firstDate = (logs.first as! Mood).createdAt {
let lastDate = (logs.last as! Mood).createdAt!
let totalDays = Calendar.current.dateComponents([.day], from: lastDate, to: firstDate).day! + 1
let loggedDays = logs.count
let noLogDays = totalDays - loggedDays
centerText = "Logged \(loggedDays) days"
chartDescription = "From \(dataController.dateCaption(for: firstDate)) to \(dataController.dateCaption(for: lastDate))"
entries = [
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .happy)), label: Emotion.happy.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-happy")),
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .neutral)), label: Emotion.neutral.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-neutral")),
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .sad)), label: Emotion.sad.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-sad")),
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .snooze)), label: Emotion.snooze.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-snooze")),
PieChartDataEntry(value: Double(noLogDays), label: "Slacking")
]
}
pieChartView.centerText = centerText
pieChartView.chartDescription?.text = chartDescription
let set = PieChartDataSet(values: entries, label: "My mood summary")
set.drawIconsEnabled = false
set.sliceSpace = 2
set.colors = ChartColorTemplates.vordiplom()
+ ChartColorTemplates.joyful()
+ ChartColorTemplates.colorful()
+ ChartColorTemplates.liberty()
+ ChartColorTemplates.pastel()
+ [UIColor(red: 51/255, green: 181/255, blue: 229/255, alpha: 1)]
let data = PieChartData(dataSet: set)
let pFormatter = NumberFormatter()
pFormatter.numberStyle = .percent
pFormatter.maximumFractionDigits = 1
pFormatter.multiplier = 1
pFormatter.percentSymbol = " %"
data.setValueFormatter(DefaultValueFormatter(formatter: pFormatter))
data.setValueFont(.systemFont(ofSize: 17, weight: .light))
data.setValueTextColor(.white)
pieChartView.data = data
pieChartView.animate(xAxisDuration: 1.4, easingOption: .easeOutBack)
}

Let's review what we've done here:

  • Declared an array variable for logs to use to build slices

  • Analyzed the segment control selected value. If the first segment is selected we requested logs from data controller for the last 30 days; otherwise - all logs

  • Prepared the default data entries to cover the no-data case

  • Declared variables for center text and chart description

  • Checked if the logs array has at least one element. If it does:

    • Took the date component from the first and the last element of the array and calculated the number of days in between that we should expect to have the logs for

    • Calculated the number of missed days

    • Composed center text and chart description based on calculated numbers

    • Composed the data array instead of previously created default one (no-data option) by populating a number for each emotion and supporting states (snooze and no-logs)

  • Assigned available captions for center text and chart description labels

  • Created and configured  PieChartDataSet  object

  • Created and configured  PieChartData  object using data set

  • Assigned the data object to data property of pie chart view

  • Animated the appearance :magicien:.

And here's the complete code of Analytics view controller:

import Foundation
import UIKit
import Charts
import CoreData
class AnalyticsViewController : UIViewController {
@IBOutlet weak var pieChartView: PieChartView!
@IBOutlet weak var timeSegment: UISegmentedControl!
let dataController = DataController()
@IBAction func timeSegmentValueChanged(_ sender: Any) {
setData()
}
func configure() {
let legend = pieChartView.legend
legend.horizontalAlignment = .right
legend.verticalAlignment = .top
legend.orientation = .vertical
}
func setData() {
var logs: [NSManagedObject]
if timeSegment.selectedSegmentIndex == 0 {
var date = dataController.today
date.addTimeInterval(-Double(30 * 3600 * 24))
logs = dataController.logs(from: date, to: nil)
}
else {
logs = dataController.logs(from: nil, to: nil)
}
var entries = [
PieChartDataEntry(value: 0, label: "No data")
]
var centerText = ""
var chartDescription = ""
if let firstDate = (logs.first as! Mood).createdAt {
let lastDate = (logs.last as! Mood).createdAt!
let totalDays = Calendar.current.dateComponents([.day], from: lastDate, to: firstDate).day! + 1
let loggedDays = logs.count
let noLogDays = totalDays - loggedDays
centerText = "Logged \(loggedDays) days"
chartDescription = "From \(dataController.dateCaption(for: firstDate)) to \(dataController.dateCaption(for: lastDate))"
entries = [
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .happy)), label: Emotion.happy.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-happy")),
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .neutral)), label: Emotion.neutral.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-neutral")),
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .sad)), label: Emotion.sad.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-sad")),
PieChartDataEntry(value: Double(dataController.count(logs: logs, emotion: .snooze)), label: Emotion.snooze.rawValue, icon: #imageLiteral(resourceName: "C5P03ch01-amazing-snooze")),
PieChartDataEntry(value: Double(noLogDays), label: "Slacking")
]
}
pieChartView.centerText = centerText
pieChartView.chartDescription?.text = chartDescription
let set = PieChartDataSet(values: entries, label: "My mood summary")
set.drawIconsEnabled = false
set.sliceSpace = 2
set.colors = ChartColorTemplates.vordiplom()
+ ChartColorTemplates.joyful()
+ ChartColorTemplates.colorful()
+ ChartColorTemplates.liberty()
+ ChartColorTemplates.pastel()
+ [UIColor(red: 51/255, green: 181/255, blue: 229/255, alpha: 1)]
let data = PieChartData(dataSet: set)
let pFormatter = NumberFormatter()
pFormatter.numberStyle = .percent
pFormatter.maximumFractionDigits = 1
pFormatter.multiplier = 1
pFormatter.percentSymbol = " %"
data.setValueFormatter(DefaultValueFormatter(formatter: pFormatter))
data.setValueFont(.systemFont(ofSize: 17, weight: .light))
data.setValueTextColor(.white)
pieChartView.data = data
pieChartView.animate(xAxisDuration: 1.4, easingOption: .easeOutBack)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
configure()
setData()
}
}

Let's test it!  This is where we are going to need some test data.  Remember to include the function that populates some dummy logs on the start.

Amazing PieChart!
Amazing PieChart!

Amazing Pie Chart is simply AMAZING! isn't it :magicien:?

How big is the world?

There's a variety of frameworks available for developers. We can identify major categories:

  • UI: Appearance, Animations, Transitions, Popups, Menus, Lists and Grids

  • Networking

  • Data store managements

  • In-app purchases

  • Push notifications

Here's a great curated list of libraries to explore on Github by Wolg - Awesome swift.

Let's Recap!

  • There are a number of ways to determine API of an external library:

    • Documentation

    • Demo project

    • Experimenting with code 

Moving forward!

Congratulations on your fantastic progress :zorro:!

In this course we’ve experimented with different applications that highlight particular visual or functional elements. This approach presents a great opportunity to analyze a number of apps and draw individual implementation techniques from them. These elements can be combined together and used as a composite solution in the following projects you’ll work on.

The good new is - you are now able to handle development challenges that appear in majority of ios projects! But there’s always more! - Keep learning!

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best
Example of certificate of achievement
Example of certificate of achievement