WeatherKit Tutorial: Getting Started
The tutorial covers exploring WeatherKit, displaying local weather forecasts and using Swift Charts for detailed predictions across locations. By Saleh Albuga.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
WeatherKit Tutorial: Getting Started
25 mins
- Getting Started
- Setting Up Your Project
- Registering App Identifiers
- Activating WeatherKit Capability
- Using WeatherService
- Displaying the Current Weather Forecast
- Exploring the Weather Data
- Getting a More Detailed Forecast
- 10-Day Weather Overview
- Presenting the Hourly Overview
- Adding a Daily Temperature Chart
- Adding an Hourly Temperature Chart
- Preparing the App for Distribution
- Where to Go From Here?
Presenting the Hourly Overview
For this, you’ll implement a horizontal list to display an overview of the weather condition every hour for the next 25 hours, starting from the current hour. As with the day’s list, you’ll create the hour details view first.
Open HourDetailsCell.swift and add the following variable definition at the start of the view struct:
var hourWeather: HourWeather?
This variable stores the HourWeather
, representing the forecast for an individual hour. The list iterator provides it. In the view body
scope, replace the existing code with:
if let hour = hourWeather {
VStack {
Text(hour.date.formatted(.dateTime.hour()))
.font(.system(size: 13.0))
Divider()
Image(systemName: hour.symbolName)
.font(.system(size: 22.0, weight: .bold))
.padding(.bottom, 3.0)
Text("\((hour.precipitationChance * 100)
.formatted(.number.precision(.fractionLength(1))))%")
.foregroundColor(.blue)
.font(.system(size: 15.0))
}
}
This view shows the weather condition icon and the precipitation chance. The precipitationChance
property returns as a Double. To display the percentage, you multiply it by 100 and show only one decimal place.
Now, open DetailedWeatherView.swift and insert the following code below the scope of if let daily = dailyForecast { ... }
:
if let hourly = hourlyForecast {
Text("Hourly Forecast").font(Font.system(.title))
Text("Next 25 hours").font(Font.system(.caption))
ScrollView(.horizontal) {
HStack(spacing: 15) {
ForEach(hourly, id: \.date) { hour in
HourDetailsCell(hourWeather: hour)
Divider()
}
}
.frame(height: 100.0)
}
.padding(.all, 5)
Divider()
// Insert the hourly temperature chart here
Divider()
}
Here, you iterate over the hours in hourlyForecast
and created an HourDetailsCell
for each hour.
Now, build and run. Go to the Detailed tab and choose a location.
Note: One of the big advantages of using SF Symbols is that you don’t need to worry about whether iOS dark mode is on or off. The symbols adapt to the device settings. Try turning on dark mode on your iPhone or, if you’re using the Simulator simply press Shift-Command-A:
Note: One of the big advantages of using SF Symbols is that you don’t need to worry about whether iOS dark mode is on or off. The symbols adapt to the device settings. Try turning on dark mode on your iPhone or, if you’re using the Simulator simply press Shift-Command-A:
Next, you’ll introduce the daily temperature chart.
Adding a Daily Temperature Chart
Charts play a crucial role in visualizing weather data. They simplify intricate data, allowing for quick comprehension. Fortunately, you don’t need a third-party framework for charts! At WWDC 2022, Apple unveiled a SwiftUI framework for charts.
In this and the following section, you’ll use this framework to construct two charts:
- A chart displaying temperature ranges: high, average and low for a 10-day span.
- A chart illustrating the temperature over 25 hours.
For both charts, the X axis represents time — either the day or hour — while the Y axis denotes the temperature.
To set the Y-axis scale in both charts, find the minimum and maximum temperatures for the respective periods. Two helper methods assist with this. Open WeatherData.swift and examine findDailyTempMinMax(_:)
in WeatherDataHelper
:
public static func findDailyTempMinMax(_ daily: Forecast) -> (min: Double, max: Double) {
let minElement = daily.min { valA, valB in
valA.lowTemperature.value < valB.lowTemperature.value
}
let min = minElement?.lowTemperature.value ?? 0
let maxElement = daily.max { valA, valB in
valA.highTemperature.value < valB.highTemperature.value
}
let max = maxElement?.highTemperature.value ?? 200
return (min, max)
}
This straightforward method accepts Forecast
and returns a tuple containing the minimum and maximum temperatures.
Because Forecast
is a RandomAccessCollection
, it adheres to the Sequence
protocol. The method employs Sequence.min(by:)
to identify the minimum and Sequence.max(by:)
to pinpoint the maximum.
The next helper method, findHourlyTempMinMax(_:)
, performs the same task but for the hourly forecast Forecast
.
Now, create the daily chart. Open DetailedWeatherView.swift and search for this comment:
// Add the daily temperature chart
Replace the comment with the following:
let range = WeatherDataHelper.findDailyTempMinMax(daily)
Chart(daily, id: \.date) { day in
LineMark( //1
x: .value("Day", day.date),
y: .value("Temperature", (day.lowTemperature.value
+ day.highTemperature.value) / 2)
)
.foregroundStyle(.orange)
.symbol(.circle)
.interpolationMethod(.catmullRom)
AreaMark( //2
x: .value("Day", day.date),
yStart: .value("Low", day.lowTemperature.value),
yEnd: .value("High", day.highTemperature.value)
)
.foregroundStyle(
Gradient(
colors: [
.orange.opacity(0.4),
.blue.opacity(0.4)
]
)
)
}
.chartForegroundStyleScale([ //3
"avg": .orange,
"low": .blue,
"high": .orange
])
.chartYScale(domain: range.min - 5...range.max + 5) //4
.chartYAxisLabel(daily[0].lowTemperature.unit.symbol) //5
.chartXAxis { //6
AxisMarks(values: .automatic(minimumStride: 10, desiredCount: 10)) { _ in
AxisGridLine()
AxisTick()
AxisValueLabel(format: .dateTime.day())
}
}
.frame(
height: 350.0
)
Look at the code. First, you call findDailyTempMinMax(_:)
to get the temperatures range as explained above and store the result in the range
variable. Then, you construct the chart passing the daily forecast data as follows:
- Draw the average temperature line by defining a
LineMark
with the date as the X axis and the temperature as the Y axis. Notice how you calculate the average(day.lowTemperature.value + day.highTemperature.value) / 2
. The line is going to be orange for contrast. - Draw an area highlighting the high and low temperatures by defining an
AreaMark
that starts from thelowTemperature
value up to thehighTemperature
value. You set the area foreground to a semi-transparent gradient ranging from blue to orange. - Add a legend with the colors representing low, average and high temperatures.
- Set the Y-axis scale, which determines the lowest and highest values displayed in the chart. However, you don’t want the highest temperature of the period to be at the very top of the chart or the lowest one at the very bottom. You want to center the line and area for better readability. To do that, you set the scale to range from five degrees below the lowest temperature and five degrees above the highest.
- Set the Y-axis label to show the temperature unit symbol.
- Set the date format in the X-axis to show only the day part of the date.
To see the chart, build and run. Switch to the Detailed tab and select one of the locations.
In the next section, you’ll add the hourly temperature chart.
Adding an Hourly Temperature Chart
Begin by opening DetailedWeatherView.swift and searching for the comment:
// Insert the hourly temperature chart here
Next, substitute the comment with:
let range = WeatherDataHelper.findHourlyTempMinMax(hourly)
Chart(hourly, id: \.date) { hour in
LineMark(
x: .value("Day", hour.date),
y: .value("Temperature", hour.temperature.value)
)
.foregroundStyle(.orange)
.symbol(.circle)
.interpolationMethod(.catmullRom)
}
.chartYScale(domain: range.min - 5...range.max + 5)
.chartYAxisLabel(hourly[0].temperature.unit.symbol)
.chartXAxis {
AxisMarks(values: .automatic(minimumStride: 10)) { _ in
AxisGridLine()
AxisTick()
AxisValueLabel(
format: .dateTime.hour().minute()
)
}
}
.frame(
height: 350.0
)
This code is very similar to the daily chart code. You first get the minimum and maximum temperatures, then construct a chart with a line indicating the temperature for each hour.
Build and run. Navigate to the Detailed tab and choose a location.
You’ll prepare your app for distribution in the upcoming section.