Swift 4의 새로운 Encodable
/ Decodable
프로토콜은 JSON (비) 직렬화를 매우 즐겁게 만듭니다. 그러나 어떤 속성을 인코딩하고 어떤 속성을 디코딩해야하는지 세밀하게 제어 할 수있는 방법을 아직 찾지 못했습니다.
수반되는 CodingKeys
열거 형에서 속성을 제외하면 프로세스에서 속성이 모두 제외 된다는 것을 알았습니다 .하지만 더 세밀하게 제어 할 수있는 방법이 있습니까?
Swift 4의 새로운 Encodable
/ Decodable
프로토콜은 JSON (비) 직렬화를 매우 즐겁게 만듭니다. 그러나 어떤 속성을 인코딩하고 어떤 속성을 디코딩해야하는지 세밀하게 제어 할 수있는 방법을 아직 찾지 못했습니다.
수반되는 CodingKeys
열거 형에서 속성을 제외하면 프로세스에서 속성이 모두 제외 된다는 것을 알았습니다 .하지만 더 세밀하게 제어 할 수있는 방법이 있습니까?
Codable
프로토콜 의 요구 사항 ( init(from:)
및 encode(to:)
)을 수동으로 구현할 수 있습니다 .
답변:
인코딩 / 디코딩 할 키 목록은라는 유형에 의해 제어됩니다 CodingKeys
.s
끝에 ). 컴파일러는이를 합성 할 수 있지만 항상 재정의 할 수 있습니다.
nickname
인코딩 과 디코딩 모두 에서 속성을 제외하고 싶다고 가정 해 보겠습니다 .
struct Person: Codable {
var firstName: String
var lastName: String
var nickname: String?
private enum CodingKeys: String, CodingKey {
case firstName, lastName
}
}
비대칭이되도록하려면 (예 : 인코딩하지만 디코딩하지 않거나 그 반대의 경우) encode(with encoder: )
및 의 자체 구현을 제공해야합니다 init(from decoder: )
.
struct Person: Codable {
var firstName: String
var lastName: String
// Since fullName is a computed property, it's excluded by default
var fullName: String {
return firstName + " " + lastName
}
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
case fullName
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
firstName = try container.decode(String.self, forKey: .firstName)
lastName = try container.decode(String.self, forKey: .lastName)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(firstName, forKey: .firstName)
try container.encode(lastName, forKey: .lastName)
try container.encode(fullName, forKey: .fullName)
}
}
nickname
이것이 작동하려면 기본값 을 제공해야합니다 . 그렇지 않으면의 속성에 할당 할 수있는 값이 없습니다 init(from:)
.
encode
비대칭 예제에서 를 제공해야 합니까? 그것이 여전히 표준 행동이기 때문에 나는 그것이 필요하다고 생각하지 않았습니다. 그냥 decode
비대칭에서 오는 그의입니다.
fullName
저장된 속성에 매핑 할 수없는 사용자 지정 인코더 및 디코더를 제공해야합니다.
구조의 많은 속성 집합에서 몇 가지 속성의 디코딩을 제외해야하는 경우 해당 속성을 선택적 속성으로 선언합니다. 선택 사항을 풀기위한 코드는 CodingKey 열거 형 아래에 많은 키를 작성하는 것보다 적습니다.
확장을 사용하여 계산 된 인스턴스 속성과 계산 된 유형 속성을 추가하는 것이 좋습니다. 코딩 가능한 컴 포밍 속성을 다른 로직과 분리하여 더 나은 가독성을 제공합니다.
인코더에서 일부 속성을 제외하는 또 다른 방법은 별도의 코딩 컨테이너를 사용할 수 있습니다.
struct Person: Codable {
let firstName: String
let lastName: String
let excludedFromEncoder: String
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
}
private enum AdditionalCodingKeys: String, CodingKey {
case excludedFromEncoder
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let anotherContainer = try decoder.container(keyedBy: AdditionalCodingKeys.self)
firstName = try container.decode(String.self, forKey: .firstName)
lastName = try container.decode(String.self, forKey: .lastName)
excludedFromEncoder = try anotherContainer(String.self, forKey: . excludedFromEncoder)
}
// it is not necessary to implement custom encoding
// func encode(to encoder: Encoder) throws
// let person = Person(firstName: "fname", lastName: "lname", excludedFromEncoder: "only for decoding")
// let jsonData = try JSONEncoder().encode(person)
// let jsonString = String(data: jsonData, encoding: .utf8)
// jsonString --> {"firstName": "fname", "lastName": "lname"}
}
디코더에도 동일한 접근 방식을 사용할 수 있습니다.
계산 된 속성을 사용할 수 있습니다.
struct Person: Codable {
var firstName: String
var lastName: String
var nickname: String?
var nick: String {
get {
nickname ?? ""
}
}
private enum CodingKeys: String, CodingKey {
case firstName, lastName
}
}
lazy var
효과적으로 런타임 속성을 사용하여 Codable에서 제외했습니다.
이 작업을 수행 할 수 있지만 궁극적으로 매우 불안정 하고 심지어 비정규 적 입니다. 나는 당신이 어디에서 왔는지 알고 있다고 생각합니다. #id
s 의 개념은 HTML에서 널리 퍼져 있지만 JSON
내가 생각하는 세계로 거의 전달되지 않습니다 . 좋은 것으로 (TM) .
일부 Codable
구조체는 JSON
재귀 해시를 사용 하여 파일을 재구성하면 파일을 잘 구문 분석 할 수 있습니다 . 즉 recipe
, 배열에 ingredients
(하나 또는 여러)를 차례로 포함하는 경우입니다 ingredient_info
. 이렇게하면 파서가 처음에 네트워크를 연결하는 데 도움이되며 실제로 필요한 경우 구조를 간단한 순회를 통해 일부 백 링크 만 제공 하면됩니다 . 이를 위해서는 귀하 JSON
와 귀하의 데이터 구조에 대한 철저한 재 작업이 필요하기 때문에 귀하가 그것에 대해 생각할 수 있도록 아이디어를 스케치 할뿐입니다. 수용 가능하다고 생각되는 경우 의견에 저에게 알려 주시면 더 자세히 설명해 드릴 수 있지만 상황에 따라 둘 중 하나를 변경할 자유가 없을 수도 있습니다.
저는 AssociatedObject와 함께 프로토콜 및 확장을 사용하여 이미지 (또는 Codable에서 제외해야하는 모든 속성) 속성을 설정하고 가져 왔습니다.
이것으로 우리는 우리 자신의 인코더와 디코더를 구현할 필요가 없습니다.
다음은 단순성을 위해 관련 코드를 유지하는 코드입니다.
protocol SCAttachmentModelProtocol{
var image:UIImage? {get set}
var anotherProperty:Int {get set}
}
extension SCAttachmentModelProtocol where Self: SCAttachmentUploadRequestModel{
var image:UIImage? {
set{
//Use associated object property to set it
}
get{
//Use associated object property to get it
}
}
}
class SCAttachmentUploadRequestModel : SCAttachmentModelProtocol, Codable{
var anotherProperty:Int
}
이제 Image 속성에 액세스하려고 할 때마다 프로토콜 (SCAttachmentModelProtocol)을 확인하는 객체에서 사용할 수 있습니다.
CodingKeys
열거 형에서 제외하는 것으로 충분하기 때문입니다.