Reputation: 3400
Getting exception *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (__SwiftValue)'
while trying to encode this Swift object to JSON. All non-optional members, objects Codable. What is the right way to encode or should use some 3rd party library?
struct MediaItem: Codable {
var key: String = ""
var filename: String = ""
}
struct NoteTask: Codable {
var id: String = ""
var notes: String = ""
var mediaList: [MediaItem] = []
}
static func addTask(task: NoteTask, callback: @escaping TaskAPICallback) {
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
let url = URL(string: postUrl)
var request : URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let params: [String: Codable?] = [
"email": task.id,
"notes": task.notes,
"fileList": task.fileList
]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
} catch {
DispatchQueue.main.async {
callback(false)
}
return
}
...
}
Upvotes: 0
Views: 1148
Reputation: 21373
The issue is that you're using JSONSerialization
instead of JSONEncoder
. JSONSerialization
is the older, Foundation/Objective-C way of writing objects to JSON. It will only work with Foundation objects (see the documentation for a complete list).
Instead, you should use JSONEncoder
. The tricky part is that JSONEncoder
can't directly encode a Dictionary
without some work on your part. There are a few ways to solve this, but if this is the only JSON format you're going to use, I'd probably just create custom keys for your structs using CodingKeys
.
struct MediaItem: Codable {
var key: String = ""
var filename: String = ""
}
struct NoteTask: Codable {
var id: String = ""
var notes: String = ""
var mediaList: [MediaItem] = []
enum CodingKeys: String, CodingKey {
case id = "email"
case notes = "notes"
case mediaList = "fileList"
}
}
static func addTask(task: NoteTask, callback: @escaping TaskAPICallback) {
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
let url = URL(string: postUrl)
var request : URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
do {
request.httpBody = try JSONEncoder().encode(task)
} catch {
DispatchQueue.main.async {
callback(false)
}
return
}
}
Upvotes: 1