[解決済み] SwiftのJSONDecodeで配列のデコードに失敗する(単一要素のデコードに失敗した場合
2022-06-30 07:54:31
質問
Swift4とCodableプロトコルを使用しているとき、次のような問題が発生しました。
JSONDecoder
で配列の要素をスキップさせる方法はないようです。
例えば、私は次のようなJSONを持っています。
[
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador."
},
{
"name": "Orange"
}
]
そして コーダブル 構造体もあります。
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
このjsonをデコードすると
let decoder = JSONDecoder()
let products = try decoder.decode([GroceryProduct].self, from: json)
結果発表
products
は空です。これは予想されることですが、JSONの2番目のオブジェクトには
"points"
キーがなく、一方
points
はオプションではありません。
GroceryProduct
構造体のオプションではありません。
問題は、どのようにすれば
JSONDecoder
に無効なオブジェクトをスキップさせることができますか?
どのように解決するのですか?
一つの方法は、与えられた値をデコードしようとするラッパーの型を使用することです。
nil
を格納します。
struct FailableDecodable<Base : Decodable> : Decodable {
let base: Base?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.base = try? container.decode(Base.self)
}
}
そして、これらの配列をデコードするために、あなたの
GroceryProduct
を埋める
Base
のプレースホルダーを埋める。
import Foundation
let json = """
[
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador."
},
{
"name": "Orange"
}
]
""".data(using: .utf8)!
struct GroceryProduct : Codable {
var name: String
var points: Int
var description: String?
}
let products = try JSONDecoder()
.decode([FailableDecodable<GroceryProduct>].self, from: json)
.compactMap { $0.base } // .flatMap in Swift 4.0
print(products)
// [
// GroceryProduct(
// name: "Banana", points: 200,
// description: Optional("A banana grown in Ecuador.")
// )
// ]
次に
.compactMap { $0.base }
をフィルタリングするために
nil
要素(デコード時にエラーを発生させたもの)を除外します。
これは、中間的な配列である
[FailableDecodable<GroceryProduct>]
しかし、もしこれを避けたいのであれば、キーが設定されていないコンテナから各要素をデコードしてラップ解除する別のラッパータイプを作成することができます。
struct FailableCodableArray<Element : Codable> : Codable {
var elements: [Element]
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
var elements = [Element]()
if let count = container.count {
elements.reserveCapacity(count)
}
while !container.isAtEnd {
if let element = try container
.decode(FailableDecodable<Element>.self).base {
elements.append(element)
}
}
self.elements = elements
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(elements)
}
}
とデコードすることになります。
let products = try JSONDecoder()
.decode(FailableCodableArray<GroceryProduct>.self, from: json)
.elements
print(products)
// [
// GroceryProduct(
// name: "Banana", points: 200,
// description: Optional("A banana grown in Ecuador.")
// )
// ]
関連
-
ArrayIndexOutOfBoundsExceptionが発生しました。7Exception: at Test.m)
-
[解決済み] Bashで文字列の配列をループする?
-
[解決済み] Swift Betaのパフォーマンス:配列のソート
-
[解決済み] Swiftでindexとelementでループを反復させる方法
-
[解決済み] ある要素が配列に含まれているかどうかを確認する方法
-
[解決済み] Bashで配列の要素を結合するには?
-
[解決済み] Swiftで配列に要素を追加する
-
[解決済み】Swiftで配列を連結またはマージするにはどうすればよいですか?
-
[解決済み] PowerShellで配列のすべてのオブジェクトの1つのプロパティの値を選択する
-
[解決済み] スライスの値を表示する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Swiftでリストアイテムのインデックスを見つける方法は?
-
[解決済み] jqで内部の配列の値に基づいてオブジェクトの配列をフィルタリングする方法は?
-
[解決済み] 反復しながら値を変更する
-
[解決済み] PowerShellで配列のすべてのオブジェクトの1つのプロパティの値を選択する
-
[解決済み] 配列中の3つの要素のうち、和が与えられた数値に最も近いものを探す
-
[解決済み] bashで$@から最初の要素を削除する [重複] [重複
-
[解決済み] Swift。配列を参照で渡す?
-
[解決済み] Swiftの配列から最小値・最大値を求める
-
[解決済み] MATLABで、bsxfunを使うのはいつが最適ですか?
-
[解決済み] SwiftのJSONDecodeで配列のデコードに失敗する(単一要素のデコードに失敗した場合