I would use nodesWithDepth
out of decodable:
this worked before:
public struct NEWTREE: Equatable, Codable {
public var Filename: String
public var GROUP: [GROUP]
public var ITEM: [ITEM]
public var CATEGORY: [CATEGORY]
public var ROOT: ROOT
but the modified not:
public struct NEWTREE: Equatable, Codable {
public var Filename: String
public var GROUP: [GROUP]
public var ITEM: [ITEM]
public var CATEGORY: [CATEGORY]
public var ROOT: ROOT
public var nodesWithDepth: [(text: String, depth: Int, type: TreeData2)]?
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
Filename = try container.decode(String.self, forKey: .Filename)
GROUP = try container.decode([GROUP].self, forKey: .GROUP)
ITEM = try container.decode([ITEM].self, forKey: .ITEM)
CATEGORY = try container.decode([CATEGORY].self, forKey: .CATEGORY)
ROOT = try container.decode(ROOT.self, forKey: .ROOT)
}
private enum CodingKeys: String, CodingKey {
case Filename
case GROUP
case ITEM
case CATEGORY
case ROOT
}
but this raise an error:
Cannot convert value of type '[[GROUP]]' to expected argument type '[GROUP].Type'
How can I fix?
Swift is confused by expressions such as
[GROUP].self
Apparently, the compiler thinks that GROUP
here refers to the property GROUP
, rather than the type GROUP
. Note that it is totally valid to add .self
to any expression, without changing what it means.
So effectively, you are passing a one-element array, containing the value of the property GROUP
. This expression has the type [[GROUP]]
, but decode
obviously expects a decodable metatype, hence the error.
Or in the case of ROOT
, you are passing the value of the ROOT
property, which has the type ROOT
, but decode
obviously expects a decodable metatype.
This behaviour can be shown with a more minimal example like this:
struct A {}
struct B {
let A: A
func f() {
print(A.self)
print([A].self)
}
}
B(A: A()).f()
print("-------")
print(A.self)
print([A].self)
The two print statements outside B
prints metatypes, whereas the ones inside B
prints an instance of A
and an array.
You can solve this ambiguity by using the long form of the array type, Array<Group>.self
GROUP = try container.decode(Array<GROUP>.self, forKey: .GROUP)
Or introduce a type alias in cases such as ROOT
:
typealias ROOTType = ROOT
...
ROOT = try container.decode(ROOTType.self, forKey: .ROOT)
But of course, none of this would have happened if you adhered to the Swift naming guidelines, and did:
var groups: [Group]
If you want the coding keys to all be capitalised, you can do it in the coding keys enum:
public struct NewTree: Equatable, Codable {
public var filename: String
public var groups: [Group]
public var items: [Item]
public var categories: [Category]
public var root: Root
// consider making the tuple here into another struct...
public var nodesWithDepth: [(text: String, depth: Int, type: TreeData2)]?
// you don't actually need to write the custom decoding logic just because you added nodesWithDepth
// Swift can figure it out from the CodingKeys enum because the
// case names match the property names
private enum CodingKeys: String, CodingKey {
case filename = "Filename"
case groups = "GROUP"
case items = "ITEM"
case categories = "CATEGORY"
case root = "ROOT"
}
}