Last active
March 3, 2019 01:47
-
-
Save 54lihaoxin/f1271b73e0c1f2650e823949baf35a4c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension KeyedDecodingContainer { | |
/// The sole purpose of this `EmptyDecodable` is allowing decoder to skip an element that cannot be decoded. | |
private struct EmptyDecodable: Decodable {} | |
/// Return successfully decoded elements even if some of the element fails to decode. | |
func safelyDecodeArray<T: Decodable>(of type: T.Type, forKey key: KeyedDecodingContainer.Key) -> [T] { | |
guard var container = try? nestedUnkeyedContainer(forKey: key) else { | |
return [] | |
} | |
var elements = [T]() | |
elements.reserveCapacity(container.count ?? 0) | |
while !container.isAtEnd { | |
/* | |
Note: | |
When decoding an element fails, the decoder does not move on the next element upon failure, so that we can retry the same element again | |
by other means. However, this behavior potentially keeps `while !container.isAtEnd` looping forever, and Apple does not offer a `.skipFailable` | |
decoder option yet. As a result, `catch` needs to manually skip the failed element by decoding it into an `EmptyDecodable` that always succeed. | |
See the Swift ticket https://bugs.swift.org/browse/SR-5953. | |
*/ | |
do { | |
elements.append(try container.decode(T.self)) | |
} catch { | |
if let decodingError = error as? DecodingError { | |
print("\(#function): skipping one element: \(decodingError)") | |
} else { | |
print("\(#function): skipping one element: \(error)") | |
} | |
_ = try? container.decode(EmptyDecodable.self) // skip the current element by decoding it into an empty `Decodable` | |
} | |
} | |
return elements | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment