Working with API objects in the Xcode Playground

Now, let's forget a bit about geometry, shapes, polygons, perimeters, and areas. We will interact with API objects in the Xcode Playground. You still need to learn many things before we can start creating object-oriented code. However, we will write some code in the Playground to interact with an existing API before we move forward with our journey into the object-oriented programming world.

Tip

The following example interacts with an iOS API, and therefore, you cannot run it in Ubuntu or in the web-based IBM Swift Sandbox. However, you will be able to run most of the examples that don't interact with iOS APIs in the forthcoming chapters.

Object-oriented programming is extremely useful when you have to interact with API objects. When Apple launched iOS 8, it introduced a Health app that provided iPhone users access to a dashboard of health and fitness data. The HealthKit framework introduced in the iOS SDK 8 allows app developers to request permissions from the users themselves to read and write specific types of health and fitness data. The framework makes it possible to ask for, create, and save health and fitness data that the users will see summarized in the Health app. This app is still a very important app in iOS 10, and the Apple Watch device in its two versions can generate very useful data for this app.

When we store and query health and fitness data, we have to use the framework to work with the units in which the values are expressed, their conversions, and localizations. For example, let's imagine an app that stores body temperature data without considering the units and their conversions. A value of 39 degrees Celsius (which is equivalent to 102.2 degrees Fahrenheit) in an adult would means that the person's body temperature is higher than normal (that is, they may have a fever). However, a value of 39 degrees Fahrenheit (equivalent to 3.88 degrees Celsius) would mean that the person's body is close to its freezing point. If our app just stores values without considering the related units and user preferences, we can have huge mistakes. If the app just saves 39 degrees and thinks that the user will always display Celsius, it will still display 39 degrees to a user whose settings use Fahrenheit as the default temperature unit. Thus, the app will provide wrong information to the user.

The data in HealthKit is always represented by a double value with an associated simple or complex unit. The units are classified into types, and it is possible to check the compatibility between units before performing conversions. We can work with HealthKit quantities and units in the Swift interactive Playground and understand how simple it is to work with an object-oriented framework. It is important to note that the Playground doesn't allow us to interact with the HealthKit data store. However, we will just play with quantities and units in a few object-oriented snippets.

Start Xcode, navigate to File | New | Playground..., enter a name for Playground, select iOS as the desired platform, click on Next, select the desired location for the Playground file, and click on Create. Xcode will display a Playground window with a line that imports UIKit and creates a string variable. You just need to add the following line to be able to work with quantities and units from the HealthKit framework, as shown in the subsequent screenshot:

    import HealthKit 

Working with API objects in the Xcode Playground

Tip

Xcode allows us to create playgrounds for any of the following platforms: iOS, Mac OS, and tvOS.

All HealthKit types start with the HK prefix. HKUnit represents a particular unit that can be either simple or complex. Simple units for temperature are degrees Celsius and degrees Fahrenheit. A complex unit for mass/volume is ounces per liter (oz/L). HKUnit supports many standard SI units (Système Internationale d'Unités in French, International System of Units in English) and non-SI units.

Add the following two lines to the Swift Playground and check the results on the right-hand side of the window; you will notice that they generate instances of HKTemperatureUnit. Thus, you created two objects that represent temperature units, as follows. The code file for the sample is included in the swift_3_oop_chapter_01_01 folder:

    let degCUnit = HKUnit.degreeCelsius() 
    let degFUnit = HKUnit.degreeFahrenheit() 

Tip

In Swift 2.x, in order to work with the APIs, it was necessary to repeat information many times. Swift 3 reduced the need to repeat information that was obvious, and therefore, we have to write less code to achieve the same goal compared with Swift 2.x. For example, in Swift 2.x, it was necessary to write HKUnit.degreeCelsiusUnit() and HKUnit.degreeFahrenheitUnit(). The HKUnit prefix makes it clear that we are talking about a unit, and therefore, Swift 3 removed the Unit word as a suffix of both HKUnit.degreeCelsiusUnit() and HKUnit.degreeFahrenheitUnit(). As a result, we can write the previously shown code that uses HKUnit.degreeCelsius() and HKUnit.degreeFahrenheit().

However, there are other ways to create objects that represent temperature units. It is also possible to use the HKUnit initializer, which returns the appropriate unit instance from its string representation. For example, the following lines also generate instances of HKTemperatureUnit for degrees in Celsius and Fahrenheit. The code file for the sample is included in the swift_3_oop_chapter_01_01 folder:

    let degCUnitFromStr = HKUnit(from: "degC") 
    let degFUnitFromStr = HKUnit(from: "degF") 

Tip

In Swift 2.x, it was necessary to use fromString instead of from to achieve the same goal shown in the previous lines. Swift 3 reduced the code that it is necessary to write to make API calls.

The following lines generate two instances of HKEnergyUnit-one for kilocalories and the other for kilojoules. The code file for the sample is included in the swift_3_oop_chapter_01_01 folder:

    let kiloCaloriesUnit = HKUnit(from: "kcal") 
    let joulesUnit = HKUnit(from: "kJ") 

The next two lines generate two instances of HKMassUnit-one for kilograms and the other for pounds. The code file for the sample is included in the swift_3_oop_chapter_01_01 folder:

    let kiloGramsUnit = HKUnit.gramUnit(with: 
    HKMetricPrefix.kilo) 
    let poundsUnit = HKUnit.pound() 

The next line generates an instance of _HKCompoundUnit because the string specifies a complex unit for mass/volume: ounces per liter (oz/L). The code file for the sample is included in the swift_3_oop_chapter_01_01 folder. The subsequent screenshot shows the results displayed in the Playground:

    let ouncesPerLiter = HKUnit(from: "oz/L") 

Working with API objects in the Xcode Playground

HKQuantity encapsulates a quantity value (Double) and the unit of measurement (HKUnit). This class doesn't provide all the operations you might expect to work with quantities and their units of measure, but it allows you to perform some useful compatibility checks and conversions.

The following lines create two HKQuantity instances with temperature units; we name the instances bodyTemperature1 and bodyTemperature2. The former uses degrees Celsius (degCUnit) and the latter degrees Fahrenheit (degFUnit). Then, the code calls the is method with the compatibleWith argument to make sure that each HKQuantity instance can be converted to degrees Fahrenheit (degFUnit). If is returns true, it means that you can convert to HKUnit, which is specified as the compatibleWith argument. We always have to call this method before calling the doubleValue method. This way, we will avoid errors when the units aren't compatible.

The doubleValue method returns the quantity value converted to the unit specified as the for argument. In this case, the two calls make sure that the value is expressed in degrees Fahrenheit, no matter what the temperature unit specified in each HKQuantity instance is. The code file for the sample is included in the swift_3_oop_chapter_01_01 folder. The screenshot that follows the given code shows the results displayed in the Playground:

    let bodyTemperature1 = HKQuantity(unit: degCUnit, 
    doubleValue: 35.2) 
    let bodyTemperature2 = HKQuantity(unit: degFUnit, 
    doubleValue: 95) 
    print(bodyTemperature1.description) 
    print(bodyTemperature2.description) 
 
    if bodyTemperature1.is(compatibleWith: degFUnit) { 
      print("Temperature #1 in Fahrenheit degrees: 
      (bodyTemperature1.doubleValue(for: degFUnit))") 
    } 
 
    if bodyTemperature2.is(compatibleWith: degFUnit) { 
      print("Temperature #2 in Fahrenheit degrees: 
      (bodyTemperature2.doubleValue(for: degFUnit))") 
    } 

Working with API objects in the Xcode Playground

The following line shows an example of the code that creates a new HKQuantity instance with a quantity and temperature unit converted from degrees Fahrenheit to degrees Celsius. There is no convert method that acts as a shortcut, so we have to call doubleValue and use it in the HKQuantity initializer, as follows. The code file for the sample is included in the swift_3_oop_chapter_01_01 folder:

    let bodyTemperature2InDegC = HKQuantity(unit: 
      degCUnit, doubleValue: 
    bodyTemperature2.doubleValue(for: degCUnit)) 

The compare method returns a ComparisonResult value that indicates whether the receiver is greater than, equal to, or less than the compatible HKQuantity value specified as an argument. For example, the following lines compare bodyTemperature1 with bodyTemperature2 and print the results of the comparison. Note that it isn't necessary to convert both the HKQuantity instances to the same unit; they just need to be compatible, and the compare method will be able to perform the comparison by making the necessary conversions under the hood. In this case, one of the temperatures is in degrees Celsius and the other is in degrees Fahrenheit. The screenshot that follows the given code shows the results displayed in the Playground:

    let bodyTemperature2InDegC = HKQuantity(unit: 
      degCUnit, doubleValue: 
    bodyTemperature2.doubleValue(for: degCUnit)) 
 
    let comparisonResult = 
    bodyTemperature1.compare(bodyTemperature2) 
    switch comparisonResult { 
      case ComparisonResult.orderedDescending: 
      print("Temperature #1 is greater than #2") 
      case ComparisonResult.orderedAscending: 
      print("Temperature #2 is greater than #1") 
      case ComparisonResult.orderedSame: 
      print("Temperature #1 is equal to Temperature #2") 
    } 
 

Working with API objects in the Xcode Playground

Tip

In many cases, the APIs removed the NS prefix in Swift 3. In Swift 2.3, the compare method returned an NSComparisonResult value. In Swift 3, the compare method returns a ComparisonResult value. In addition, the APIs in Swift 3 use lowerCamelCase for enumeration values. Therefore, the NSComparisonResult.OrderedDescending value in Swift 2.3 is ComparisonResult.orderedDescending in Swift 3.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.111.70