I am wondering if there is a different approach I could take here aside from the nested do { try } catch { do { try } catch { do { try } catch { ... }}}}}} approach I am currently using.
Similarly, any comments or suggestions on the switch self { ... } block would be appreciated.
UniversalPayload is to encode and decode a JSON payload object which contains three properties op: Int, t: String?, s: Int?, which have a known type and structure, and one property d: JSONAble? which is known to conform to JSON but has an unknown structure otherwise.
Will someone please suggest improvements to the following code?
struct UniversalPayload: Codable {
typealias GenericPayloadData = [String: PayloadDatum?]
var op: Int
var t: String?
var s: Int?
var d: GenericPayloadData?
enum PayloadDatum: Codable {
case array([PayloadDatum])
case bool(Bool)
case int(Int)
case null(Bool)
case object(GenericPayloadData)
case string(String)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
var value: PayloadDatum?
// Pyramid of do do do do doooom
do { value = try .bool(container.decode(Bool.self)) } catch {
do { value = try .int(container.decode(Int.self)) } catch {
do { value = try .string(container.decode(String.self)) } catch {
do { value = try .array(container.decode([PayloadDatum].self)) } catch {
do { value = try .object(container.decode(GenericPayloadData.self)) } catch {
value = .null(container.decodeNil())
} // catch .object
} // catch .array
} // catch .string
} // catch .int
} // catch .bool
self = value!
} // init
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .array(let arrayValue):
try? container.encode(arrayValue)
case .bool(let boolValue):
try? container.encode(boolValue)
case .int(let intValue):
try? container.encode(intValue)
case .object(let objectValue):
try? container.encode(objectValue)
case .string(let stringValue):
try? container.encode(stringValue)
case .null(let nullValue):
if nullValue {
try? container.encodeNil()
}
else {
let context = EncodingError.Context(codingPath: encoder.codingPath,
debugDescription: "Unknown Type")
throw EncodingError.invalidValue(self, context )
} // else
} // switch
} // encode
} // PayloadDatum
} // UniversalPayload
Post
Replies
Boosts
Views
Activity
I am reading through the Encoding and Decoding Custom Types article, and I am seeing to encoder: Encoder and from decoder: Decoder throughout the examples.
I am new to Swift, and it isn't really clear to me why it is to encoder: Encoder and not just encoder: Encoder.
Here is a longer snippet for more context:
extension Coordinate: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(latitude, forKey: .latitude)
try container.encode(longitude, forKey: .longitude)
var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
try additionalInfo.encode(elevation, forKey: .elevation)
}
}
What is the purpose of to and from within these examples?
I have been trying to find an answer to this question, but searching for "what is the purpose of to in swift" and other variants has been remarkably unsuccessful.