You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

44 lines
1.6 KiB

2 years ago
  1. // From: https://medium.com/@kewindannerfjordremeczki/swift-4-0-decodable-heterogeneous-collections-ecc0e6b468cf
  2. import Foundation
  3. // MARK: - ClassFamily
  4. /// To support a new class family, create an enum that conforms to this protocol and contains the different types.
  5. protocol ClassFamily: Decodable {
  6. /// The discriminator key.
  7. static var discriminator: Discriminator { get }
  8. /// Returns the class type of the object corresponding to the value.
  9. func getType() -> AnyObject.Type
  10. }
  11. // MARK: - Discriminator
  12. /// Discriminator key enum used to retrieve discriminator fields in JSON payloads.
  13. enum Discriminator: String, CodingKey {
  14. case type = "ty"
  15. }
  16. extension KeyedDecodingContainer {
  17. /// Decode a heterogeneous list of objects for a given family.
  18. /// - Parameters:
  19. /// - heterogeneousType: The decodable type of the list.
  20. /// - family: The ClassFamily enum for the type family.
  21. /// - key: The CodingKey to look up the list in the current container.
  22. /// - Returns: The resulting list of heterogeneousType elements.
  23. func decode<T: Decodable, U: ClassFamily>(_: [T].Type, ofFamily family: U.Type, forKey key: K) throws -> [T] {
  24. var container = try nestedUnkeyedContainer(forKey: key)
  25. var list = [T]()
  26. var tmpContainer = container
  27. while !container.isAtEnd {
  28. let typeContainer = try container.nestedContainer(keyedBy: Discriminator.self)
  29. let family: U = try typeContainer.decode(U.self, forKey: U.discriminator)
  30. if let type = family.getType() as? T.Type {
  31. list.append(try tmpContainer.decode(type))
  32. }
  33. }
  34. return list
  35. }
  36. }