WatchOS (Swift): Horoscope Application

andreslopezrm

Andres Lopez

Posted on March 31, 2019

WatchOS (Swift): Horoscope Application

In this tutorial an application for WatchOS will be made, based on consulting a REST API of horoscopes.

Requirements

  • Xcode 10.2 or higher
  • Mac OS Mojave or higher
  • IPhone simulator
  • Apple Watch Simulator

Creation of the project

Open XCode and create a new WatchOS project.

xcode

The Include Notification Scene option is unchecked and the location where the project is saved is selected.

xcode

First screen

xcode

Drag a table element.

xcode

Two labels are added inside the table:

  • First label with the following alignment properties.

xcode

  • Second label with the following alignment properties.

xcode

The Row element of the table is assigned the identifier with the same name Row.

xcode

A Row class is created that inherits from NSObject and we link the corresponding outlets.


import WatchKit

class Row: NSObject {
    @IBOutlet weak var lblIcon: WKInterfaceLabel!

    @IBOutlet weak var lblZodiac: WKInterfaceLabel!
}

Enter fullscreen mode Exit fullscreen mode

The code of the Interface Controller is as follows:


import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

    @IBOutlet weak var table: WKInterfaceTable!


    let zodiac = [
        ("♈", "Aries"),
        ("♉", "Taurus"),
        ("♊", "Gemini"),
        ("♋", "Cancer"),
        ("♌", "Leo"),
        ("♍", "Virgo"),
        ("♎", "Libra"),
        ("♏", "Scorpio"),
        ("♐", "Sagittarius"),
        ("♑", "Capricorn"),
        ("♒", "Aquarius"),
        ("♓", "Pisces")
    ]

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        // Configure interface objects here.


        table.setNumberOfRows(zodiac.count, withRowType: "Row")

        for (index, sign) in zodiac.enumerated() {
            guard let row = table.rowController(at: index) as? Row else { return }
            row.lblIcon.setText(sign.0)
            row.lblZodiac.setText(sign.1)
        }
    }

    override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
        print(zodiac[rowIndex].1)

        let context = ["sing": zodiac[rowIndex].1]

        presentController(withName: "Results", context: context)
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }

}

Enter fullscreen mode Exit fullscreen mode

Model

The following structure is used for the response model:


import Foundation

struct Horoscope: Codable {
    var currentDate: String
    var description: String

    enum CodingKeys: String, CodingKey {
        case currentDate = "current_date", description
    }
}

Enter fullscreen mode Exit fullscreen mode

Second Screen

It is responsible for consuming the API, its interface is very simple and is built only with tags, which work very similar to iOS.

xcode

The Results Controller code is the following:


import WatchKit
import Foundation


class ResultsController: WKInterfaceController {

    @IBOutlet weak var lblSing: WKInterfaceLabel!
    var sing: String?

    @IBOutlet weak var lblDate: WKInterfaceLabel!

    @IBOutlet weak var lblDescription: WKInterfaceLabel!

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        // Configure interface objects here.

        guard let context = context as? [String: String] else { return }
        guard let sing = context["sing"] else { return }

        lblSing.setText(sing)

        DispatchQueue.global(qos: .userInteractive).async {
            self.fetchData(sing: sing.lowercased())
        }
    }

    func fetchData(sing: String) {
        guard let url = URL(string: "https://aztro.sameerkumar.website/?sign=\(sing)&day=today") else { return }

        print("https://aztro.sameerkumar.website/?sign=\(sing)&day=today")
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "POST"


        URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
            if let data = data {
                self.parse(data)
            } else {
                print("vacio")
            }
        }.resume()
    }

    func parse(_ contens: Data) {
        let decoder = JSONDecoder()

        guard let result = try? decoder.decode(Horoscope.self, from: contens) else { return }

        DispatchQueue.main.async {
            self.lblDate.setText(result.currentDate)
            self.lblDescription.setText(result.description)
        }
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }
}

Enter fullscreen mode Exit fullscreen mode

The application running

xcode

xcode

Conclusions

Consuming a REST API in WatchOS is relatively easy and very similar to how it is done in iOS. You can find the project code in the following github repository.

💖 💪 🙅 🚩
andreslopezrm
Andres Lopez

Posted on March 31, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related