Swift中如何从Tomorrow.io API仅提取温度数值数据
提取Tomorrow.io API返回的温度数值
我知道这是新手常遇到的问题,但它真的困扰着我!以下是我当前的Swift代码:
func WeatherAPI() async throws { let parameters = [ "location": "Greenvale Victoria", "fields": ["temperature"], "units": "metric", "timesteps": ["1h"], "startTime": "2025-03-03T00:00:00+11:00", "endTime": "nowPlus24h", "dailyStartHour": 6, "timezone": "Australia/Melbourne" ] as [String : Any?] let postData = try JSONSerialization.data(withJSONObject: parameters, options: []) let url = URL(string: "https://api.tomorrow.io/v4/timelines")! var components = URLComponents(url: url, resolvingAgainstBaseURL: true)! let queryItems: [URLQueryItem] = [ URLQueryItem(name: "apikey", value: "This ain't for you!"), ] components.queryItems = components.queryItems.map { $0 + queryItems } ?? queryItems var request = URLRequest(url: components.url!) request.httpMethod = "POST" request.timeoutInterval = 10 request.allHTTPHeaderFields = [ "accept": "application/json", "Accept-Encoding": "deflate, gzip, br", "content-type": "application/json" ] request.httpBody = postData let (data, temperature) = try await URLSession.shared.data(for: request) print(String(decoding: data, as: UTF8.self)) }
调用Tomorrow.io的/v4/timelines接口后,print返回了完整结构的JSON:
{"data":{"timelines":[{"timestep":"1h","endTime":"2025-03-04T13:00:00+11:00","startTime":"2025-03-03T00:00:00+11:00","intervals":[{"startTime":"2025-03-03T00:00:00+11:00","values":{"temperature":14.3}},{"startTime":"2025-03-03T01:00:00+11:00","values":{"temperature":13.9}},{"startTime":"2025-03-03T02:00:00+11:00","values":{"temperature":13.4}},{"startTime":"2025-03-03T03:00:00+11:00","values":{"temperature":13.1}},{"startTime":"2025-03-03T04:00:00+11:00","values":{"temperature":12.7}},{"startTime":"2025-03-03T05:00:00+11:00","values":{"temperature":12.5}},{"startTime":"2025-03-03T06:00:00+11:00","values":{"temperature":11.6}},{"startTime":"2025-03-03T07:00:00+11:00","values":{"temperature":11.3}},{"startTime":"2025-03-03T08:00:00+11:00","values":{"temperature":12.3}},{"startTime":"2025-03-03T09:00:00+11:00","values":{"temperature":14.4}},{"startTime":"2025-03-03T10:00:00+11:00","values":{"temperature":16.4}},{"startTime":"2025-03-03T11:00:00+11:00","values":{"temperature":17.6}},{"startTime":"2025-03-03T12:00:00+11:00","values":{"temperature":18.8}},{"startTime":"2025-03-03T13:00:00+11:00","values":{"temperature":19.7}},{"startTime":"2025-03-03T14:00:00+11:00","values":{"temperature":20.2}},{"startTime":"2025-03-03T15:00:00+11:00","values":{"temperature":20}},{"startTime":"2025-03-03T16:00:00+11:00","values":{"temperature":19.6}},{"startTime":"2025-03-03T17:00:00+11:00","values":{"temperature":19}},{"startTime":"2025-03-03T18:00:00+11:00","values":{"temperature":18.1}},{"startTime":"2025-03-03T19:00:00+11:00","values":{"temperature":17}},{"startTime":"2025-03-03T20:00:00+11:00","values":{"temperature":15.9}},{"startTime":"2025-03-03T21:00:00+11:00","values":{"temperature":15.3}},{"startTime":"2025-03-03T22:00:00+11:00","values":{"temperature":14.7}},{"startTime":"2025-03-03T23:00:00+11:00","values":{"temperature":14.2}},{"startTime":"2025-03-04T00:00:00+11:00","values":{"temperature":13.7}},{"startTime":"2025-03-04T01:00:00+11:00","values":{"temperature":13.3}},{"startTime":"2025-03-04T02:00:00+11:00","values":{"temperature":13.1}},{"startTime":"2025-03-04T03:00:00+11:00","values":{"temperature":12.7}},{"startTime":"2025-03-04T04:00:00+11:00","values":{"temperature":12.3}},{"startTime":"2025-03-04T05:00:00+11:00","values":{"temperature":11.9}},{"startTime":"2025-03-04T06:00:00+11:00","values":{"temperature":11.5}},{"startTime":"2025-03-04T07:00:00+11:00","values":{"temperature":11.2}},{"startTime":"2025-03-04T08:00:00+11:00","values":{"temperature":12.3}},{"startTime":"2025-03-04T09:00:00+11:00","values":{"temperature":14.9}},{"startTime":"2025-03-04T10:00:00+11:00","values":{"temperature":17.3}},{"startTime":"2025-03-04T11:00:00+11:00","values":{"temperature":20.6}},{"startTime":"2025-03-04T12:00:00+11:00","values":{"temperature":24.8}},{"startTime":"2025-03-04T13:00:00+11:00","values":{"temperature":28}}]}]}}
我只想要温度数值,希望能直接像这样访问:
// 示例 if let temperatures = extractedTemperatures { print(temperatures[0]) // 第一个温度值 print(temperatures[1]) // 第二个温度值 print(temperatures[2]) // 第三个温度值 }
解决方案
方法一:使用Codable(推荐,类型安全)
先定义对应JSON结构的Codable模型:
struct WeatherResponse: Codable { let data: WeatherData } struct WeatherData: Codable { let timelines: [Timeline] } struct Timeline: Codable { let intervals: [Interval] } struct Interval: Codable { let values: Values } struct Values: Codable { let temperature: Double }
然后修改你的API函数,解析数据并提取温度数组:
func WeatherAPI() async throws -> [Double] { let parameters = [ "location": "Greenvale Victoria", "fields": ["temperature"], "units": "metric", "timesteps": ["1h"], "startTime": "2025-03-03T00:00:00+11:00", "endTime": "nowPlus24h", "dailyStartHour": 6, "timezone": "Australia/Melbourne" ] as [String : Any] // 去掉Optional,避免JSONSerialization报错 let postData = try JSONSerialization.data(withJSONObject: parameters, options: []) let url = URL(string: "https://api.tomorrow.io/v4/timelines")! var components = URLComponents(url: url, resolvingAgainstBaseURL: true)! components.queryItems = [URLQueryItem(name: "apikey", value: "This ain't for you!")] var request = URLRequest(url: components.url!) request.httpMethod = "POST" request.timeoutInterval = 10 request.allHTTPHeaderFields = [ "accept": "application/json", "Accept-Encoding": "deflate, gzip, br", "content-type": "application/json" ] request.httpBody = postData let (data, _) = try await URLSession.shared.data(for: request) let response = try JSONDecoder().decode(WeatherResponse.self, from: data) // 提取所有温度值 let temperatures = response.data.timelines.flatMap { $0.intervals.map { $0.values.temperature } } return temperatures }
调用方式:
Task { do { let temperatures = try await WeatherAPI() print(temperatures[0]) // 14.3 print(temperatures[1]) // 13.9 print(temperatures[2]) // 13.4 } catch { print(error) } }
方法二:使用JSONSerialization(快速实现,无类型安全)
如果不想定义模型,可以直接解析JSON提取温度:
func WeatherAPI() async throws -> [Double] { // ... 前面的请求代码和原来一致 ... let (data, _) = try await URLSession.shared.data(for: request) guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any], let dataDict = json["data"] as? [String: Any], let timelines = dataDict["timelines"] as? [[String: Any]], let firstTimeline = timelines.first, let intervals = firstTimeline["intervals"] as? [[String: Any]] else { throw NSError(domain: "ParseError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to parse JSON"]) } let temperatures = intervals.compactMap { interval in guard let values = interval["values"] as? [String: Double], let temp = values["temperature"] else { return nil } return temp } return temperatures }
调用方式和方法一相同。
内容的提问来源于stack exchange,提问作者Train Lover
相关产品推荐
相关产品推荐

