缺少json文件/struct错误
我已经试着让这个代码工作了6个小时。我得到错误:“无法转换数据,无法读取,因为它丢失了。”我不知道文件丢失时,我的模型(结构)中是否有错误。我是否需要为每个json字典编写一个结构?目前,我只将这些JSON字典制作成一个结构,这是我实际需要的。完整的JSON文件可以在上找到。我想能够打印日出、日落和太阳正午的时间,以及太阳正午的太阳高度。现在是凌晨1点,我很绝望。晚安缺少json文件/struct错误,json,swift,parsing,Json,Swift,Parsing,我已经试着让这个代码工作了6个小时。我得到错误:“无法转换数据,无法读取,因为它丢失了。”我不知道文件丢失时,我的模型(结构)中是否有错误。我是否需要为每个json字典编写一个结构?目前,我只将这些JSON字典制作成一个结构,这是我实际需要的。完整的JSON文件可以在上找到。我想能够打印日出、日落和太阳正午的时间,以及太阳正午的太阳高度。现在是凌晨1点,我很绝望。晚安 class ViewController: NSViewController { @IBOutlet weak
class ViewController: NSViewController {
@IBOutlet weak var sunriseField: NSTextField!
@IBOutlet weak var sunsetField: NSTextField!
@IBOutlet weak var daylengthField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
let url = "https://api.met.no/weatherapi/sunrise/2.0/.json?lat=40.7127&lon=-74.0059&date=2020-12-22&offset=-05:00"
getData(from: url)
// Do any additional setup after loading the view.
}
private func getData(from url: String) {
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: {data, response, error in
guard let data = data, error == nil else {
print("something went wrong")
return
}
var result: MyTime?
do {
result = try JSONDecoder().decode(MyTime.self, from: data)
}
catch {
print("failed to convert \(error.localizedDescription)")
}
guard let json = result else {
return
}
let sunrise1 = json.sunrise.time
DispatchQueue.main.async { [weak self] in
self?.sunriseField.stringValue = sunrise1
}
print(json)
})
task.resume()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
struct MyData : Codable {
let location : Location
let meta : Meta
}
struct MyTime : Codable {
let solarnoon : Solarnoon
let sunset : Sunset
let sunrise : Sunrise
}
struct Location : Codable {
let height : String
let time : [MyTime]
let longitude : String
let latitude : String
}
struct Meta : Codable {
let licenseurl : String
}
struct Solarnoon : Codable {
let desc : String
let time : String
let elevation : String
}
struct Sunrise : Codable {
let desc : String
let time : String
}
struct Sunset : Codable {
let time : String
let desc : String
}
从json数据(第二项)来看,您至少需要:
struct MyTime : Codable {
let solarnoon : Solarnoon?
let sunset : Sunset?
let sunrise : Sunrise?
}
你需要:
var result: MyData?
do {
result = try JSONDecoder().decode(MyData.self, from: data)
}
catch {
print("----> error failed to convert \(error)")
}
从json数据(第二项)来看,您至少需要:
struct MyTime : Codable {
let solarnoon : Solarnoon?
let sunset : Sunset?
let sunrise : Sunrise?
}
你需要:
var result: MyData?
do {
result = try JSONDecoder().decode(MyData.self, from: data)
}
catch {
print("----> error failed to convert \(error)")
}
您没有真正的SwiftUI类,但这是一个不同的问题。我将致力于修复getData()。我试着对其进行广泛的评论,但如果您有任何问题,请告诉我
private func getData(from url: String) {
// Personally I like converting the string to a URL to unwrap it and make sure it is valid:
guard let url = URL(string: urlString) else {
print("Bad URL: \(urlString)")
return
}
let config = URLSessionConfiguration.default
// This will hold the request until you have internet
config.waitsForConnectivity = true
URLSession.shared.dataTask(with: url) { data, response, error in
// A check for a bad response
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
print("Bad Server Response")
return
}
if let data = data {
// You can print(data) here that will shown you the number of bytes returned for debugging.
//This work needs to be done on the main thread:
DispatchQueue.main.async {
let decoder = JSONDecoder()
if let json = try? decoder.decode(MetDecoder.self, from: data){
print(json)
//At this point, you have your data in a struct
self.sunriseTime = json.dailyData?.solarData?.first?.sunrise?.time
}
}
}
}
.resume()
}
对于结构,您只需要将它们用于您试图解析的数据。如果你不需要,不要担心。我会将其作为一个单独的类,名为MetDecoder,或者其他对您有意义的类,并指示JSON的解码器。您还将注意到,我更改了一些变量的名称。您可以这样做,只要您使用CodingKeys枚举将JSON转换为结构,如dailyData=“location”
等。这是难看的JSON,我不确定为什么Met决定所有内容都应该是字符串,但此解码器经过测试,可以工作:
import Foundation
// MARK: - MetDecoder
struct MetDecoder: Codable {
let dailyData: DailyData?
enum CodingKeys: String, CodingKey {
case dailyData = "location"
}
}
// MARK: - Location
struct DailyData: Codable {
let solarData: [SolarData]?
enum CodingKeys: String, CodingKey {
case solarData = "time"
}
}
// MARK: - Time
struct SolarData: Codable {
let sunrise, sunset: RiseSet?
let solarnoon: Position?
let date: String?
enum CodingKeys: String, CodingKey {
case sunrise, sunset, solarnoon, date
}
}
// MARK: - HighMoon
struct Position: Codable {
let time: String?
let desc, elevation, azimuth: String?
}
// MARK: - Moonrise
struct RiseSet: Codable {
let time: String?
let desc: String?
}
你应该看看美国国家气象局对我们做了什么来获取JSON。最后,在处理JSON时,我发现以下页面非常有用:
这将帮助您解析出在浏览器中返回的大量文本
这将把JSON解析成像Swift这样的编程语言。我将警告您,解析可能会在Swift中产生一些非常难看的结构,但它为您提供了一个良好的开端。我使用了这两个网站来回答这个问题。你没有真正的SwiftUI类,但这是一个不同的问题。我将致力于修复getData()。我试着对其进行广泛的评论,但如果您有任何问题,请告诉我
private func getData(from url: String) {
// Personally I like converting the string to a URL to unwrap it and make sure it is valid:
guard let url = URL(string: urlString) else {
print("Bad URL: \(urlString)")
return
}
let config = URLSessionConfiguration.default
// This will hold the request until you have internet
config.waitsForConnectivity = true
URLSession.shared.dataTask(with: url) { data, response, error in
// A check for a bad response
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
print("Bad Server Response")
return
}
if let data = data {
// You can print(data) here that will shown you the number of bytes returned for debugging.
//This work needs to be done on the main thread:
DispatchQueue.main.async {
let decoder = JSONDecoder()
if let json = try? decoder.decode(MetDecoder.self, from: data){
print(json)
//At this point, you have your data in a struct
self.sunriseTime = json.dailyData?.solarData?.first?.sunrise?.time
}
}
}
}
.resume()
}
对于结构,您只需要将它们用于您试图解析的数据。如果你不需要,不要担心。我会将其作为一个单独的类,名为MetDecoder,或者其他对您有意义的类,并指示JSON的解码器。您还将注意到,我更改了一些变量的名称。您可以这样做,只要您使用CodingKeys枚举将JSON转换为结构,如dailyData=“location”
等。这是难看的JSON,我不确定为什么Met决定所有内容都应该是字符串,但此解码器经过测试,可以工作:
import Foundation
// MARK: - MetDecoder
struct MetDecoder: Codable {
let dailyData: DailyData?
enum CodingKeys: String, CodingKey {
case dailyData = "location"
}
}
// MARK: - Location
struct DailyData: Codable {
let solarData: [SolarData]?
enum CodingKeys: String, CodingKey {
case solarData = "time"
}
}
// MARK: - Time
struct SolarData: Codable {
let sunrise, sunset: RiseSet?
let solarnoon: Position?
let date: String?
enum CodingKeys: String, CodingKey {
case sunrise, sunset, solarnoon, date
}
}
// MARK: - HighMoon
struct Position: Codable {
let time: String?
let desc, elevation, azimuth: String?
}
// MARK: - Moonrise
struct RiseSet: Codable {
let time: String?
let desc: String?
}
你应该看看美国国家气象局对我们做了什么来获取JSON。最后,在处理JSON时,我发现以下页面非常有用:
这将帮助您解析出在浏览器中返回的大量文本
这将把JSON解析成像Swift这样的编程语言。我将警告您,解析可能会在Swift中产生一些非常难看的结构,但它为您提供了一个良好的开端。我使用了这两个站点来回答这个问题。苹果的新框架Combine有助于简化异步获取请求所需的代码。我在上面@Yrb的响应中使用了MetDecoder(您可以接受他的答案),并修改了getData()函数。只需确保在顶部导入联合收割机即可
import Combine
var sunriseTime: String?
var sunsetTime: String?
var solarNoonTime: String?
var solarNoonElevation: String?
func getData() {
let url = URL(string: "https://api.met.no/weatherapi/sunrise/2.0/.json?lat=40.7127&lon=-74.0059&date=2020-12-22&offset=-05:00")!
URLSession.shared.dataTaskPublisher(for: url)
// fetch on background thread
.subscribe(on: DispatchQueue.global(qos: .background))
// recieve response on main thread
.receive(on: DispatchQueue.main)
// ensure there is data
.tryMap { (data, response) in
guard
let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
// decode JSON data to MetDecoder
.decode(type: MetDecoder.self, decoder: JSONDecoder())
// Handle results
.sink { (result) in
// will return success or failure
print("completion: \(result)")
} receiveValue: { (value) in
// if success, will return MetDecoder
// here you can update your view
print("value: \(value)")
if let solarData = value.dailyData?.solarData?.first {
self.sunriseTime = solarData.sunrise?.time
self.sunsetTime = solarData.sunset?.time
self.solarNoonTime = solarData.solarnoon?.time
self.solarNoonElevation = solarData.solarnoon?.elevation
}
}
// After recieving response, the URLSession is no longer needed & we can cancel the publisher
.cancel()
}
苹果的新框架Combine有助于简化异步获取请求所需的代码。我在上面@Yrb的响应中使用了MetDecoder(您可以接受他的答案),并修改了getData()函数。只需确保在顶部导入联合收割机即可
import Combine
var sunriseTime: String?
var sunsetTime: String?
var solarNoonTime: String?
var solarNoonElevation: String?
func getData() {
let url = URL(string: "https://api.met.no/weatherapi/sunrise/2.0/.json?lat=40.7127&lon=-74.0059&date=2020-12-22&offset=-05:00")!
URLSession.shared.dataTaskPublisher(for: url)
// fetch on background thread
.subscribe(on: DispatchQueue.global(qos: .background))
// recieve response on main thread
.receive(on: DispatchQueue.main)
// ensure there is data
.tryMap { (data, response) in
guard
let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
// decode JSON data to MetDecoder
.decode(type: MetDecoder.self, decoder: JSONDecoder())
// Handle results
.sink { (result) in
// will return success or failure
print("completion: \(result)")
} receiveValue: { (value) in
// if success, will return MetDecoder
// here you can update your view
print("value: \(value)")
if let solarData = value.dailyData?.solarData?.first {
self.sunriseTime = solarData.sunrise?.time
self.sunsetTime = solarData.sunset?.time
self.solarNoonTime = solarData.solarnoon?.time
self.solarNoonElevation = solarData.solarnoon?.elevation
}
}
// After recieving response, the URLSession is no longer needed & we can cancel the publisher
.cancel()
}
能否将
打印(“未能转换\(错误.本地化说明)”)
更改为打印(“未能转换\(错误)”)
,并告诉我们您得到了什么?能否将打印(“未能转换\(错误.本地化说明)”)
更改为打印(“未能转换\(错误)”
,告诉我们你得到了什么?这个答案很美!我还在为联合收割机绞尽脑汁……这个答案真是太美了!我还在用我的头缠绕联合收割机。。。