首页

动手练一练,做一个简单的天气预报应用(weather app two)【中】

By 前端达人
Published in D-案例练习
August 10, 2022
1 min read
动手练一练,做一个简单的天气预报应用(weather app two)【中】

在本教程系列的第一部分中,我们学习了如何使用 CoreLocation 获取用户的当前位置及其坐标。接下来通过我们获取坐标的信息去请求天气相关的接口,本篇文章将使用免费的 OpenWeather API 来获取天气。

获取天气

现在我们获得了坐标,我们可以使用 OpenWeather API 轻松获取该位置的天气信息。您首先需要去上述网站创建一个免费帐户,然后在我的 API 密钥页面下,获取您的 API 密钥。

OpenWeather_home_page.png
OpenWeather_home_page.png

现在,让我们回到 Xcode。在 Managers 文件夹下,我们创建一个新的 Swift 文件并将其命名为 WeatherManager.swift 。在新文件中引入以下内容。

// ./Managers/WeatherManager.swift

import Foundation
import CoreLocation

接下来我们创建 WeatherManager 类

// ./Managers/WeatherManager.swift

class WeatherManager {
}

在这个类中只定义一个函数 getCurrentWeather 。它使用 WWDC21 大会中介绍的新异步接口请求方法,示例代码如下。

func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> ResponseBody {
    guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?lat=\(latitude)&lon=\(longitude)&appid=YOUR_API_KEY&units=metric") else { fatalError("Missing URL") }

    let urlRequest = URLRequest(url: url)

    let (data, response) = try await URLSession.shared.data(for: urlRequest)

    guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching data") }

    let decodedData = try JSONDecoder().decode(ResponseBody.self, from: data)

    return decodedData
}

在函数的第一行,您会看到一个 API 的请求URL。这是我们将要调用的API。我们正在向 API 传参纬度和经度,以及 API 密钥。使用 API 密钥记得替换成自己申请的 API KEY。最后,我们返回decodedData。在同一个 WeatherManager 文件中,在类的正下方添加一个 ResponseBody 模型。您可以从头开始,也可以简单地复制下面的内容。最后借助 JSONDecoder 将尝试将数据解码成对应的内容。

// ./Managers/WeatherManager.swift

struct ResponseBody: Decodable {
    var coord: CoordinatesResponse
    var weather: [WeatherResponse]
    var main: MainResponse
    var name: String
    var wind: WindResponse

    struct CoordinatesResponse: Decodable {
        var lon: Double
        var lat: Double
    }

    struct WeatherResponse: Decodable {
        var id: Double
        var main: String
        var description: String
        var icon: String
    }

    struct MainResponse: Decodable {
        var temp: Double
        var feels_like: Double
        var temp_min: Double
        var temp_max: Double
        var pressure: Double
        var humidity: Double
    }

    struct WindResponse: Decodable {
        var speed: Double
        var deg: Double
    }
}

extension ResponseBody.MainResponse {
    var feelsLike: Double { return feels_like }
    var tempMin: Double { return temp_min }
    var tempMax: Double { return temp_max }
}

在 ContentView 文件中,我们将在顶部创建一个 WeatherManager 的新实例。

// ./Views/ContentView.swift

var weatherManager = WeatherManager()

添加一个 weather 的状态变量

// ./Views/ContentView.swift

@State var weather: ResponseBody?

在 if let location = locationManager.location 语句中,我们将用 if else 语句替换文本。在 if 中,我们现在将显示一个 Text(接口请求成功后,调用显示)。在 else 中,由于是异步调用,接口请求过程中,我们添加一个 ProgressView 加载状态 ,当它出现时,我们将调用任务修饰符(因为我们使用的是 async await )。在任务修饰符内部,我们从 weatherManager 调用 getCurrentWeather 方法,并将结果保存在天气状态中。

// ./Views/ContentView.swift

if let weather = weather {
    Text("Weather data fetched!")
} else {
    ProgressView()
        .task {
            do {
                weather = try await weatherManager.getCurrentWeather(latitude: location.latitude, longitude: location.longitude)
            } catch {
                print("Error getting weather: \(error)")
            }
        }
}

测试应用

现在,将手机连接到 Mac,在手机上构建应用程序,然后尝试测试应用程序。一旦你分享了你的位置,你应该会在屏幕上看到文本天气数据,这意味着我们确实得到了天气数据。很好!如果不是这种情况,请向上滚动以查看您是否错过了一个步骤或忘记添加一些代码。

添加预览数据

接下来为了开发方便,我们需要准备一些预览数据,避免在真机上进行测试。我们来创建一个新的视图文件,天气相关的数据将会被展现出来。我们在 Views 目录下创建 WeatherView.swift 文件,定义个继承 ResponseBody 变量的 weather 变量。

**var weather: ResponseBody**

接下来我们在Preview Content 文件夹下创建一个 weatherData.json 的文件,此文件的内容可以通过 https://api.openweathermap.org/data/2.5/weather?q=New York&appid=YOURAPIKEY&units=metric 这个地址请求获取JSON文件的内容,记得替换你的API参数和城市名称。将返回的内容复制到 JSON 文件中,示例JSON内容如下

{
    "coord": {
        "lon": -74.006,
        "lat": 40.7143
    },
    "weather": [
        {
            "id": 804,
            "main": "Clouds",
            "description": "overcast clouds",
            "icon": "04d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 3.42,
        "feels_like": 0.51,
        "temp_min": 1.36,
        "temp_max": 5.28,
        "pressure": 1015,
        "humidity": 73
    },
    "visibility": 10000,
    "wind": {
        "speed": 3.13,
        "deg": 274,
        "gust": 4.92
    },
    "clouds": {
        "all": 90
    },
    "dt": 1638298034,
    "sys": {
        "type": 2,
        "id": 2039034,
        "country": "US",
        "sunrise": 1638273608,
        "sunset": 1638307792
    },
    "timezone": -18000,
    "id": 5128581,
    "name": "New York",
    "cod": 200
}

然后在Preview Content 目录下新建个 ModelData.swift 的文件,解析 weatherData.json 中的数据,示例代码如下:

//
//  ModelData.swift
//  WeatherApp
//
//  Created by 林森 on 2022/7/3.
//

import Foundation

var previewWeather: ResponseBody = load("weatherData.json")

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data

    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find \(filename) in main bundle.")
    }

    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }

    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

回到 WeatherView ,将 previewWeather 变量传递给预览。

// ./Views/WeatherView.swift

struct WeatherView_Previews: PreviewProvider {
    static var previews: some View {
        WeatherView(weather: previewWeather)
    }
}

由于我们从 OpenWeather API 获取的数据将返回双精度数,因此我们需要将双精度数四舍五入舍去小数部分,保留整数部分。接下来让我们创建一个新的 Extensions.swift 文件,我们将在其中存储一些工具函数的扩展。如下代码所示我们添加 Double extension 扩展,将所有双精度数四舍五入保留整数部分。

// ./Extensions.swift

extension Double {
    func roundDouble() -> String {
        return String(format: "%.0f", self)
    }
}

接下来

非常棒,我们现在获得了天气数据,并为 WeatherView 试图准备了天气预览的数据和字符串处理扩展。在下篇文章,我们继续完善 WeatherView 的UI部分。

版权声明

注:本文属于原创文章,版权属于「前端达人」公众号及 SwiftUI.cc 所有,谢绝一切形式的转载

更多精彩内容,请关注「前端达人」

欢迎关注「前端达人」
欢迎关注「前端达人」


Tags

#project
Previous Article
一个简单个人展示页(personal page)
前端达人

前端达人

专注前端知识分享

Table Of Contents

1
获取天气
2
测试应用
3
添加预览数据
4
接下来
5
版权声明

Related Posts

动手练一练,做一个简单的天气预报应用(weather app three)【下】
August 11, 2022
1 min

前端学习站

前端达人官网VUE官网React官网TypeScript官网

公众号:前端达人

京ICP备16033841号-8