我正在使用Swift 4 JSONEncoder.我有一个Codable带有可选属性的结构,我希望这个属性在null值为时在生成的JSON数据中显示为值nil.但是,JSONEncoder丢弃该属性并且不将其添加到JSON输出.有没有办法配置,JSONEncoder以便它保留密钥并null在这种情况下将其设置为?
下面的代码片段会产生{"number":1},但我更愿意给它{"string":null,"number":1}:
struct Foo: Codable {
var string: String? = nil
var number: Int = 1
}
let encoder = JSONEncoder()
let data = try! encoder.encode(Foo())
print(String(data: data, encoding: .utf8)!)
Run Code Online (Sandbox Code Playgroud) 更新到Xcode 9.3(使用Swift 4.1)后,发现以下问题:
创建一个空项目,向其添加一个新的.swift文件并创建两个新类:
class CodableOne: Codable {
let some: String
}
class CodableTwo: Codable {
var some: String
}
Run Code Online (Sandbox Code Playgroud)
建立成功
添加CodableOne类型的新常量CodableTwo:
class CodableOne: Codable {
let some: String
let another: CodableTwo
}
class CodableTwo: Codable {
var some: String
}
Run Code Online (Sandbox Code Playgroud)
建立成功
现在将类移动CodableTwo到另一个文件(例如ViewController.swift)
构建失败.
现在有一个错误,它不会消失.Codable类不应该需要初始化器(如前面的步骤所示).
关于这背后可能出现的问题及如何解决的任何想法将不胜感激!
PS Code在Xcode 9.2中不存在.也不清理项目/构建路径,重新安装Xcode 9.3也有帮助.
我设法让JSON和plist编码和解码都工作,但只能通过直接调用特定对象上的编码/解码函数.
例如:
struct Test: Codable {
var someString: String?
}
let testItem = Test()
testItem.someString = "abc"
let result = try JSONEncoder().encode(testItem)
Run Code Online (Sandbox Code Playgroud)
这很好,没有问题.
但是,我试图获得一个只接受Codable协议一致性类型的函数并保存该对象.
func saveObject(_ object: Encodable, at location: String) {
// Some code
let data = try JSONEncoder().encode(object)
// Some more code
}
Run Code Online (Sandbox Code Playgroud)
这会导致以下错误:
无法使用类型'(Encodable)'的参数列表调用'encode'
看看编码函数的定义,似乎它应该能够接受Encodable,除非Value是一些我不知道的奇怪类型.
open func encode<Value>(_ value: Value) throws -> Data where Value : Encodable
Run Code Online (Sandbox Code Playgroud) 我一直在玩,Codable并从文件中读取和写入JSON.现在我想写一个Coder可以读写iOS .strings文件的自定义.谁能帮我这个?我发现协议Encoder和Decoder,但我不知道我应该实现此:
class StringsEncoder {}
extension StringsEncoder: Encoder {
var codingPath: [CodingKey?] {
return []
}
var userInfo: [CodingUserInfoKey : Any] {
return [:]
}
func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey {
}
func unkeyedContainer() -> UnkeyedEncodingContainer {
}
func singleValueContainer() -> SingleValueEncodingContainer {
}
}
extension StringsEncoder: Decoder {
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey {
}
func unkeyedContainer() throws -> …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用Swift 4中的新JSONDecoder/Encoder找到符合swift协议的编码/解码结构数组的最佳方法.
我举了一个例子来说明问题:
首先,我们有一个协议Tag和一些符合这个协议的类型.
protocol Tag: Codable {
var type: String { get }
var value: String { get }
}
struct AuthorTag: Tag {
let type = "author"
let value: String
}
struct GenreTag: Tag {
let type = "genre"
let value: String
}
Run Code Online (Sandbox Code Playgroud)
然后我们有一个Type文章,它有一个标签数组.
struct Article: Codable {
let tags: [Tag]
let title: String
}
Run Code Online (Sandbox Code Playgroud)
最后,我们对文章进行编码或解码
let article = Article(tags: [AuthorTag(value: "Author Tag Value"), GenreTag(value:"Genre Tag Value")], title: "Article Title")
let jsonEncoder = JSONEncoder()
let jsonData = try …Run Code Online (Sandbox Code Playgroud) 我正在使用Codable带有JSON数据的Swift 4 协议.我的数据被格式化为在根级别有一个键,其中一个对象值包含我需要的属性,例如:
{
"user": {
"id": 1,
"username": "jdoe"
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个User可以解码user密钥的结构:
struct User: Codable {
let id: Int
let username: String
}
Run Code Online (Sandbox Code Playgroud)
由于id和username是的性质user,而不是在根级别,我需要使一个包装类型,如下所示:
struct UserWrapper: Codable {
let user: User
}
Run Code Online (Sandbox Code Playgroud)
然后,我可以通过UserWrapper,解码JSON ,并User解码.它似乎是很多冗余代码,因为我需要在我拥有的每种类型上都有一个额外的包装器.有没有办法避免这种包装模式或更正确/优雅的方式来处理这种情况?
我想使用DecodableSwift 4中引入的新协议解码XML文档,但是,似乎没有符合Decoder协议的XML解码器的现有实现.
我的计划是使用SWXMLHash库来解析XML,然后可能使该XMLIndexer库中的类扩展Decoder协议,以便可以使用XMLIndexer(XMLIndexer返回SWXMLHash.parse(xmlString))实例初始化我的模型.
我的问题是我不知道如何实现Decoder协议,我似乎无法在网上找到任何解释它是如何完成的资源.我发现的每一个资源都严格地提到了JSONDecoderSwift标准库中包含的类,没有找到的资源解决了创建自己的自定义解码器的问题.
我正在用Swift的Codable替换旧的JSON解析代码,并且遇到了一些麻烦.我想这不是一个可编码的问题,因为它是一个DateFormatter问题.
从结构开始
struct JustADate: Codable {
var date: Date
}
Run Code Online (Sandbox Code Playgroud)
和一个json字符串
let json = """
{ "date": "2017-06-19T18:43:19Z" }
"""
Run Code Online (Sandbox Code Playgroud)
现在让我们解码
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let data = json.data(using: .utf8)!
let justADate = try! decoder.decode(JustADate.self, from: data) //all good
Run Code Online (Sandbox Code Playgroud)
但是,如果我们更改日期以使其具有小数秒,例如:
let json = """
{ "date": "2017-06-19T18:43:19.532Z" }
"""
Run Code Online (Sandbox Code Playgroud)
现在它打破了.日期有时会以小秒数回归,有时则不会.我以前解决它的方式是在我的映射代码中我有一个转换函数,它尝试使用和不使用小数秒的dateFormats.我不太确定如何使用Codable来处理它.有什么建议?
我有一个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) 我的数据结构有一个枚举作为键,我希望下面自动解码.这是一个错误还是一些配置问题?
import Foundation
enum AnEnum: String, Codable {
case enumValue
}
struct AStruct: Codable {
let dictionary: [AnEnum: String]
}
let jsonDict = ["dictionary": ["enumValue": "someString"]]
let data = try! JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
let decoder = JSONDecoder()
do {
try decoder.decode(AStruct.self, from: data)
} catch {
print(error)
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误就是这个,似乎把dict与数组混淆了.
typeMismatch(Swift.Array,Swift.DecodingError.Context(codingPath:[Optional(__ lldb_expr_85.AStruct.(CodingKeys in _0E2FD0A9B523101D0DCD67578F72D1DD).dictionary)],debugDescription:"预计会解码数组,但会找到一个字典."))