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から除外されました。
これは可能ですが、最終的には非常に迅速でなく、JSONyでさえありません。あなたがどこから来たのかはわかります。sの概念は#id
HTMLで普及していますが、それが良いことだJSON
と思う世界に持ち込まれることはめったにありません。(TM)。
一部のCodable
構造体はJSON
、再帰ハッシュを使用してファイルを再構築すると、ファイルを正常に解析できます。つまりrecipe
、配列にingredients
(1つまたは複数の)が含まれているだけの場合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
列挙型から除外するだけで十分です。