read parse jsonserialization ios json swift4 codable

ios - parse - string to json swift 4



Codifique el valor nulo como nulo con JSONEncoder (2)

Sí, pero tendrás que escribir tu propio codificador; no puedes usar el predeterminado

struct Foo: Codable { var string: String? = nil var number: Int = 1 func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(number, forKey: .number) try container.encode(string, forKey: .string) } }

Codificar un opcional directamente codificará un nulo, como lo está buscando.

Si este es un caso de uso importante para usted, puede considerar abrir un defecto en bugs.swift.org para solicitar que se agregue un nuevo indicador de OpcScodagingStrategy opcional en JSONEncoder para que coincida con el DateEncodingStrategy existente, etc. para implementarlo realmente en Swift hoy, pero entrar en el sistema de seguimiento sigue siendo útil a medida que Swift evoluciona.)

Edición: A las preguntas de Paulo a continuación, esto se envía a la versión genérica de encode<T: Encodable> porque Optional ajusta a Encodable . Esto se implementa en Codable.swift esta manera:

extension Optional : Encodable /* where Wrapped : Encodable */ { @_inlineable // FIXME(sil-serialize-all) public func encode(to encoder: Encoder) throws { assertTypeIsEncodable(Wrapped.self, in: type(of: self)) var container = encoder.singleValueContainer() switch self { case .none: try container.encodeNil() case .some(let wrapped): try (wrapped as! Encodable).__encode(to: &container) } } }

Esto envuelve la llamada a encodeNil , y creo que dejar que stdlib maneje Optionals como otro Encodable es mejor que tratarlos como un caso especial en nuestro propio codificador y llamar a encodeNil nosotros mismos.

Otra pregunta obvia es por qué funciona así en primer lugar. Ya que Opcional es Codificable, y la conformidad Codificable generada codifica todas las propiedades, ¿por qué "codificar todas las propiedades a mano" funciona de manera diferente? La respuesta es que el generador de conformidad incluye un caso especial para Optionals :

// Now need to generate `try container.encode(x, forKey: .x)` for all // existing properties. Optional properties get `encodeIfPresent`. ... if (varType->getAnyNominal() == C.getOptionalDecl() || varType->getAnyNominal() == C.getImplicitlyUnwrappedOptionalDecl()) { methodName = C.Id_encodeIfPresent; }

Esto significa que cambiar este comportamiento requeriría cambiar la conformidad generada automáticamente, no JSONEncoder (lo que también significa que probablemente sea muy difícil configurarlo en Swift de hoy ...)

Estoy usando JSONEncoder Swift 4. Tengo una estructura Codable con una propiedad opcional, y me gustaría que esta propiedad se muestre como un valor null en los datos JSON producidos cuando el valor es nil . Sin embargo, JSONEncoder descarta la propiedad y no la agrega a la salida JSON. ¿Hay alguna forma de configurar JSONEncoder para que conserve la clave y la establezca en null en este caso?

Ejemplo

El siguiente fragmento de código produce {"number":1} , pero me gustaría que me diera {"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)!)


Tuve el mismo problema. Se solucionó creando un diccionario desde la estructura sin usar JSONEncoder. Puedes hacerlo de una manera relativamente universal. Aquí está mi código:

struct MyStruct: Codable { let id: String let regionsID: Int? let created: Int let modified: Int let removed: Int? enum CodingKeys: String, CodingKey, CaseIterable { case id = "id" case regionsID = "regions_id" case created = "created" case modified = "modified" case removed = "removed" } var jsonDictionary: [String : Any] { let mirror = Mirror(reflecting: self) var dic = [String: Any]() var counter = 0 for (name, value) in mirror.children { let key = CodingKeys.allCases[counter] dic[key.stringValue] = value counter += 1 } return dic } } extension Array where Element == MyStruct { func jsonArray() -> [[String: Any]] { var array = [[String:Any]]() for element in self { array.append(element.jsonDictionary) } return array } }

Puede hacer esto sin las Claves de codificación (si los nombres de los atributos de la tabla en el lado del servidor son iguales a los nombres de las propiedades de su estructura). En ese caso, simplemente use el ''nombre'' de mirror.children.

Si necesita CodingKeys, no olvide agregar el protocolo CaseIterable . Eso hace posible utilizar la variable allCases .

Tenga cuidado con las estructuras anidadas: por ejemplo, si tiene una propiedad con una estructura personalizada como tipo, también debe convertirla en un diccionario. Puedes hacer esto en el bucle for.

La extensión Array es necesaria si desea crear una matriz de diccionarios MyStruct.