loading...
Cover image for WatchOS (Swift): Horoscope Application

WatchOS (Swift): Horoscope Application

andreslopezrm profile image ALR ・3 min read

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!
}

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()
    }

}

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
    }
}

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()
    }
}

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.

Discussion

pic
Editor guide
Collapse
andreslopezrm profile image
ALR Author

Thanks!!!!

Collapse
calo0012 profile image