Swift URLRequest解析平台REST APIJSON并解码为Struct

问题描述

我正在尝试使用特定的功能,这些功能在适用于Parse Platform(服务器)的iOS SDK中不可用,但是我知道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

成功返回数据的

{ “结果”:[ { “ __type”:“日期”, “ iso”:“ 2020-08-29T07:00:00.000Z” }, { “ __type”:“日期”, “ iso”:“ 2020-08-29T07:09:00.000Z” } ]}

原始数据来自3行,其中2行共享相同的TeeTime:

Parse Dashboard screenshot

以及Rested.app输出的屏幕截图:

Rested.app Output screenshot

现在,我正在尝试将其转换为我的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()
            
        }
    }
}

控制台输出为:

解码错误:keyNotFound(CodingKeys(stringValue:“ __type”,intValue: nil),Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue: “结果”,intValue:无),_JSONKey(stringValue:“索引0”,intValue: 0)],debugDescription:“没有与键关联的值 CodingKeys(stringValue:“ __type”,intValue:nil)(“ __type”)。“, 底层错误:nil))

我的第一个猜测是属性定义开头的2个下划线“ __type”吗?

解决方法

@Larme在开头帖子的评论中提供的答案。 @gcharita的贡献是,如果语法与我正在执行的其他测试的结构相同(不是-参见下文),则我的语法应该有效。

发生错误是因为未使用distinct=TeeTime过滤器,所以返回的结果是不同的JSON结构。因此,它正在返回一个JSON对象,其中包含该类的所有数据行,而不是我的TeeTimeData结构对象中指定的那些行。

在网址字符串的末尾附加?distinct=TeeTime可以解决此问题并返回:

解码后的数据:TeeTimeData(结果:[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"]代码。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...