我有一个API,有时会id在JSON中作为Int 返回一个特定的键(在本例中),有时它将返回与String相同的键.如何使用codable来解析JSON?
struct GeneralProduct: Codable {
var price:Double!
var id:String?
var name:String!
private enum CodingKeys: String, CodingKey {
case price = "p"
case id = "i"
case name = "n"
}
init(price:Double? = nil, id: String? = nil, name: String? = nil) {
self.price = price
self.id = id
self.name = name
}
}
Run Code Online (Sandbox Code Playgroud)
我不断收到此错误消息:Expected to decode String but found a number instead.返回数字的原因是因为id字段为空,并且当id字段为空时,它默认返回0作为可编码标识为数字的ID.我基本上可以忽略ID键但是可编码不会让我根据我的知识忽略它.处理这个问题的最佳方法是什么?
这是JSON.它非常简单
工作
{
"p":2.12,
"i":"3k3mkfnk3",
"n":"Blue Shirt"
}
Run Code Online (Sandbox Code Playgroud)
错误 - 因为系统中没有id,它返回0作为默认值,可编码显然看作是与字符串相对的数字.
{
"p":2.19, …Run Code Online (Sandbox Code Playgroud) 我的iOS应用程序有一个非常常见的设置:它向使用JSON对象响应的API服务器进行HTTP查询.然后将这些JSON对象解析为适当的Swift对象.
最初,我将属性划分为必需的属性和可选属性,主要基于我的API服务器的数据库要求.例如id,email和name如此他们使用非可选类型需要的字段.其他人可以NULL在数据库中,因此它们是可选类型.
class User {
let id: Int
let email: String
let profile: String?
let name: String
let motive: String?
let address: String?
let profilePhotoUrl: String?
}
Run Code Online (Sandbox Code Playgroud)
最近,我开始怀疑这是否是一个很好的设置.我发现尽管某些属性可能总是在数据库中,但这并不意味着这些属性将始终包含在JSON响应中.
例如,在"用户配置文件"页面中,需要所有这些字段才能正确显示视图.因此,JSON响应将包括所有这些字段.但是,对于列出用户名称的视图,我不需要email或者id,JSON响应也可能不包括这些属性.不幸的是,这将导致错误和解析JSON响应到斯威夫特对象时,因为应用程序崩溃预计的应用id,email,name是永远不会比零.
我正在考虑将Swift对象的所有属性更改为可选对象,但感觉就像丢掉了这种特定于语言的功能的所有好处.此外,我将不得不编写更多代码行来打开应用程序中其他地方的所有这些选项.
另一方面,JSON对象本质上不能与Swift的严格静态类型和nil检查非常互操作,所以最好简单地接受这种烦恼.
我应该过渡到每个属性作为选项的模型吗?或者,还有更好的方法?我很感激这里有任何评论.
我需要Decodable正确解码(协议)一个不精确的十进制值,从这个问题我了解如何正确处理十进制实例化,但是在解码时如何做到这一点?
如果尝试将任何数字初始化为字符串
if let value = try! container.decode(String.self, forKey: .d) {
self.taxAmount = Decimal(string: value)
}
Run Code Online (Sandbox Code Playgroud)
我明白了Fatal Error: "Expected to decode String but found a number instead."
如果尝试将 130.43 初始化为十进制
if let value = try! container.decode(Decimal.self, forKey: .d) {
//value.description is 130.43000000000002048
self.d = Decimal(string: value.description)
//making subtotal to be also 130.43000000000002048 and not 130.43
}
Run Code Online (Sandbox Code Playgroud)
解码时有什么方法可以使用这个构造函数吗?
NSDecimalNumber(string: "1.66")NSDecimalNumber(value: 166).dividing(by: 100)Decimal(166)/Decimal(100)Decimal(sign: .plus, exponent: -2, significand: 166)以下是我从外部服务收到的 JSON 的简化版本:
{
"priceAfterTax": 150.00, …Run Code Online (Sandbox Code Playgroud) 如您所知,Codable是Swift 4中的新功能,因此我们将从模型的较早初始化过程转向这一点。通常我们使用以下方案
class LoginModal
{
let cashierType: NSNumber
let status: NSNumber
init(_ json: JSON)
{
let keys = Constants.LoginModal()
cashierType = json[keys.cashierType].number ?? 0
status = json[keys.status].number ?? 0
}
}
Run Code Online (Sandbox Code Playgroud)
在JSON cashierType键中可能会丢失,因此我们将默认值设置为0
现在,使用Codable做到这一点非常容易,如下所示
class LoginModal: Coadable
{
let cashierType: NSNumber
let status: NSNumber
}
Run Code Online (Sandbox Code Playgroud)
如上所述,键可能会丢失,但是我们不希望将Model Variables作为可选变量,因此我们如何使用Codable实现此目的。
谢谢
如果我们编码了符合Codable并希望使用具有新属性的新类代码解码这些对象的类的对象,那么需要什么代码才能使该新属性成为非可选的,并为其属性赋予默认值?
老班:
class Item: Codable {
let id: String
}
Run Code Online (Sandbox Code Playgroud)
新班级:
class Item: Codable {
let id: String
let title: String
}
Run Code Online (Sandbox Code Playgroud)
当使用新格式的代码解码以旧格式保存的对象时,title将找不到任何属性,并且解码将不起作用。
我们可以通过创建title一个可选的String?.
但是我们如何实现title作为非可选的保持String,并在解码每个对象时给它一个默认值?
PS:这是完整的代码。没有指定编码密钥,也没有编写来自解码器的自定义初始化。
我知道classand的基本概念,struct但是为 API 创建模型以获取数据并告诉我优缺点更有效。
以前我不使用可选的模型。相反,我给了它一些价值。IE
class CompanyInfo : Codable {
var NameEn : String = ""
var CityEn : String = ""
var Website : String = ""
var Email : String = ""
var Phone : String = ""
var Fax : String = ""
}
Run Code Online (Sandbox Code Playgroud)
但是当它null从 API获得一些价值时。即"Fax": null然后应用程序崩溃,因为它无法使用以下行解析数据
let data = try JSONDecoder().decode(dataModel.self, from: dataSet)
Run Code Online (Sandbox Code Playgroud)
定义模型的最佳方法是什么,这样我就不需要解开可选项或给它默认值。
我在解码 JSON 时遇到问题。我正在尝试解码我的 JSON
let temp = try JSONDecoder().decode([LastTemperatureResponse].self, from: data).
我的Codable结构如下:
struct LastTemperatureResponseElement: Codable {
let measurement: Measurement
}
struct Measurement: Codable {
let ts: String
let sensors: [VportSensor]
}
struct VportSensor: TemperatureSensor, Codable {
var lastUpdate: String!
let address, description: String
let status: String
let temperature: Double
}
Run Code Online (Sandbox Code Playgroud)
好吧,如果我试图解码我的 JSON,我会收到很清楚的错误消息
keyNotFound(CodingKeys(stringValue: "status", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "measurement", intValue: nil), CodingKeys(stringValue: "sensors", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No …Run Code Online (Sandbox Code Playgroud)