I'm creating a custom Decoder class with the corresponding KeyedDecodingContainerProtocol adhering class. When the generic decode method is called with the property to decode, is there a way to instantiate a class/struct if it adheres to my own DBObject protocol that has an init method?
I can create a custom method for decoding and instantiate the object:
func decodeObject<T: DBObject>(_ type: DBObject.Type, forKey key: K) throws -> T {
guard let value = dict[key.stringValue] as? String else {
throw DictDecoderError.missingValueForKey(key.stringValue)
}
guard let dbObject = T(db: db, key: value) else {
throw DictDecoderError.invalidNestedObject(key.stringValue, value)
}
return dbObject
}
But then how do I call it properly?
if T.self is DBObject.Type {
return try decodeObject(T.Type, forKey: key) as! T
Doesn't work because it cannot infer T
Assuming DBObject is not PAT:
func decodeObject(_ type: DBObject.Type, forKey key: K) throws -> DBObject {
guard let value = dict[key.stringValue] as? String else {
throw DictDecoderError.missingValueForKey(key.stringValue)
}
guard let dbObject = type.init(db: db, key: value) else {
throw DictDecoderError.invalidNestedObject(key.stringValue, value)
}
return dbObject
}
// call it
if let dynamicType = T.self as? DBObject.Type {
return try decodeObject(dynamicType, forKey: key) as! T
}
1 Like
That worked perfectly. Thanks! How would I decode an array of DBObjects? (and what is a PAT protocol?)
I have this for testing the property is a DBObject array:
else if let dynamicType = T.self as? [DBObject].Type {
return try decodeObjectArray(dynamicType, forKey: key) as! T
}
But not sure how to write the decode function:
func decodeObjectArray(_ type: [DBObject].Type, forKey key: K) throws -> [DBObject] {
guard let values = dict[key.stringValue] as? [String] else {
throw DictDecoderError.missingValueForKey(key.stringValue)
}
var objectValues: [DBObject] = []
for value in values {
if let dbObject = // how do I initialize? {
objectValues.append(dbObject)
}
}
return objectValues
}
Because you can't convert a dynamic type:
let dynamicType = T.self as? DBObject.Type
to a static type:
func decodeObject<StaticType: DBObject>(_ type: StaticType, forKey key: K) throws -> T
Also you can't create a dynamic type from PAT:
let dynamicType = T.self as? RawRepresentable.Type // NO
let value = dynamicType.init(rawValue: /* what type? */)
As for DBObject array:
protocol DBObjectArrayMarker {
static var elementType: DBObject.Type { get }
}
extension Array: DBObjectArrayMarker where Element: DBObject {
static var elementType: DBObject.Type {
return Element.self
}
}
func decodeObjectArray(_ type: DBObjectArrayMarker.Type, forKey key: K) throws -> [DBObject] {
guard let values = dict[key.stringValue] as? [String] else {
throw DictDecoderError.missingValueForKey(key.stringValue)
}
var objectValues: [DBObject] = []
for value in values {
if let dbObject = type.elementType.init(db: db, key: value) {
objectValues.append(dbObject)
}
}
return objectValues
}
// call it
if let dynamicType = T.self as? DBObjectArrayMarker.Type {
return try decodeObjectArray(dynamicType, forKey: key) as! T
}
Thanks for your help! You can see the results of your help here: