Swift URLRequest 解析平台 REST API (JSON) 并解码为结构
Swift URLRequest to Parse Platform REST API (JSON) & Decode into Struct
我正在尝试使用可用的 iOS SDK for Parse Platform(服务器)中不可用的特定功能,但我知道这些功能可用于 REST API。专门使用 DISTINCT 查询。
在我的开发计算机 (Rested.app) 上使用 Parse Dashboard 和 REST API 客户端应用程序,我已验证以下查询按预期完成:
curl -X GET \
-H "X-Parse-Application-Id: someAppID" \
-H "X-Parse-Master-Key: someKey" \
-G \
--data-urlencode "distinct=TeeTime" \
http://somehost:1337/parse/aggregate/CompEntry
成功returns数据:
{
"results": [
{
"__type": "Date",
"iso": "2020-08-29T07:00:00.000Z"
},
{
"__type": "Date",
"iso": "2020-08-29T07:09:00.000Z"
}
] }
原始数据来自,共有3行,其中2行共享相同的TeeTime:
以及 Rested.app 输出的屏幕截图:
现在我正在尝试将其转换为我的 Swift / iOS 项目。
我正在尝试将下载的数据移动到一个新结构中来表示对象,使用 Codable/Decodable 方法并匹配 JSON 属性 名称。到目前为止,我的代码如下(也内嵌了一些注释)。 Struct 定义出现在单独的 .swift 文件中,但只要在主要 ViewController 定义之外。
struct TeeTimeData: Codable {
let results: [Results]
}
struct Results: Codable {
let __type: String
let iso: String // TODO: THIS SHOULD BE A DIFFERENT DATA TYPE - I HAVE PICKED HARDER DATA TYPE TO START WITH!
}
然后在主 ViewController 结构中:
class ViewController: UIViewController {
@IBAction func buttonGetTeeTimes(_ sender: UIButton) {
if let url = URL(string: "http://somehost:1337/parse/aggregate/CompEntry") {
var request = URLRequest(url: url)
request.addValue("someAppID", forHTTPHeaderField: "X-Parse-Application-Id")
request.addValue("someKey", forHTTPHeaderField: "X-Parse-Master-Key")
request.httpMethod = "GET"
let params = ["distinct": "TeeTime"] // TODO: THIS VAR IS NOT ACTUALLY BEING TIED TO THE REQUEST EITHER - 2nd PROBLEM...
let session = URLSession(configuration: .default)
let requestTask = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print("API Error: \(error)")
}
if let dataUnwrap = data {
// TODO: MOVE THIS INTO NEW CLASS (DataModel, etc)
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(TeeTimeData.self, from: dataUnwrap)
print(decodedData)
} catch {
print("Decode Error: \(error)")
}
}
}
requestTask.resume()
}
}
}
控制台输出为:
Decode Error: keyNotFound(CodingKeys(stringValue: "__type", intValue:
nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue:
"results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue:
0)], debugDescription: "No value associated with key
CodingKeys(stringValue: "__type", intValue: nil) ("__type").",
underlyingError: nil))
我的第一个猜测是 属性 定义开头的 2 个下划线“__type”?
@Larme 在开场评论中提供的答案 post。来自@gcharita 的贡献,如果我的语法 应该 与我正在执行的其他测试的结构相同(事实并非如此 - 见下文)。
发生错误是因为返回的结果是不同的 JSON 结构,因为未应用 distinct=TeeTime
过滤器。所以它返回一个 JSON 对象,其中包含来自 class 的所有数据行,而不是我的 TeeTimeData 结构对象中指定的那些。
将 ?distinct=TeeTime
附加到 URL 字符串的末尾解决了该问题并且 returns:
Decoded data: TeeTimeData(results: [Parse_2.Results(__type: "Date",
iso: "2020-08-29T07:00:00.000Z"), Parse_2.Results(__type: "Date", iso:
"2020-08-29T07:09:00.000Z")])
这也意味着我不再需要 let params = ["distinct": "TeeTime"]
代码。
我正在尝试使用可用的 iOS SDK for Parse Platform(服务器)中不可用的特定功能,但我知道这些功能可用于 REST API。专门使用 DISTINCT 查询。
在我的开发计算机 (Rested.app) 上使用 Parse Dashboard 和 REST API 客户端应用程序,我已验证以下查询按预期完成:
curl -X GET \
-H "X-Parse-Application-Id: someAppID" \
-H "X-Parse-Master-Key: someKey" \
-G \
--data-urlencode "distinct=TeeTime" \
http://somehost:1337/parse/aggregate/CompEntry
成功returns数据:
{ "results": [ { "__type": "Date", "iso": "2020-08-29T07:00:00.000Z" }, { "__type": "Date", "iso": "2020-08-29T07:09:00.000Z" } ] }
原始数据来自,共有3行,其中2行共享相同的TeeTime:
以及 Rested.app 输出的屏幕截图:
现在我正在尝试将其转换为我的 Swift / iOS 项目。
我正在尝试将下载的数据移动到一个新结构中来表示对象,使用 Codable/Decodable 方法并匹配 JSON 属性 名称。到目前为止,我的代码如下(也内嵌了一些注释)。 Struct 定义出现在单独的 .swift 文件中,但只要在主要 ViewController 定义之外。
struct TeeTimeData: Codable {
let results: [Results]
}
struct Results: Codable {
let __type: String
let iso: String // TODO: THIS SHOULD BE A DIFFERENT DATA TYPE - I HAVE PICKED HARDER DATA TYPE TO START WITH!
}
然后在主 ViewController 结构中:
class ViewController: UIViewController {
@IBAction func buttonGetTeeTimes(_ sender: UIButton) {
if let url = URL(string: "http://somehost:1337/parse/aggregate/CompEntry") {
var request = URLRequest(url: url)
request.addValue("someAppID", forHTTPHeaderField: "X-Parse-Application-Id")
request.addValue("someKey", forHTTPHeaderField: "X-Parse-Master-Key")
request.httpMethod = "GET"
let params = ["distinct": "TeeTime"] // TODO: THIS VAR IS NOT ACTUALLY BEING TIED TO THE REQUEST EITHER - 2nd PROBLEM...
let session = URLSession(configuration: .default)
let requestTask = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print("API Error: \(error)")
}
if let dataUnwrap = data {
// TODO: MOVE THIS INTO NEW CLASS (DataModel, etc)
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(TeeTimeData.self, from: dataUnwrap)
print(decodedData)
} catch {
print("Decode Error: \(error)")
}
}
}
requestTask.resume()
}
}
}
控制台输出为:
Decode Error: keyNotFound(CodingKeys(stringValue: "__type", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "__type", intValue: nil) ("__type").", underlyingError: nil))
我的第一个猜测是 属性 定义开头的 2 个下划线“__type”?
@Larme 在开场评论中提供的答案 post。来自@gcharita 的贡献,如果我的语法 应该 与我正在执行的其他测试的结构相同(事实并非如此 - 见下文)。
发生错误是因为返回的结果是不同的 JSON 结构,因为未应用 distinct=TeeTime
过滤器。所以它返回一个 JSON 对象,其中包含来自 class 的所有数据行,而不是我的 TeeTimeData 结构对象中指定的那些。
将 ?distinct=TeeTime
附加到 URL 字符串的末尾解决了该问题并且 returns:
Decoded data: TeeTimeData(results: [Parse_2.Results(__type: "Date", iso: "2020-08-29T07:00:00.000Z"), Parse_2.Results(__type: "Date", iso: "2020-08-29T07:09:00.000Z")])
这也意味着我不再需要 let params = ["distinct": "TeeTime"]
代码。