I'm trying to deserialise XML to a class using the example provided at the end of the readme, but it's raising the same compile time error as originally provoked this question.
method 'deserialize' in non-final class 'Element' must return
Self
to conform to protocol 'XMLElementDeserializable'
I have tried to use the example as verbatim as possible (although changing quite a bit as Date, a struct, is now mainly used over NSDate), but I am still getting the same issue.
This is the code I'm trying to use (essentially identical just stripped down for clarity
import Foundation
import SWXMLHash
class Element: XMLElementDeserializable {
public static func deserialize(element: SWXMLHash.XMLElement) throws -> Self {
return value(Element())
}
private static func value<T>(_ element: Element) -> T {
return element as! T
}
}
deserialize
implementation does not implement the one which is blueprintedYour own deserialize
function does not implement the one blueprinted from XMLElementDeserializable
, meaning a default implementation of deserialize
(from XMLElementDeserializable
) will become available to your class Element
. This default implementation is a throwing erroneous one, which is the source of your somewhat obfuscated error message.
From the source code of the SWXMLHash framework
/// Provides XMLElement deserialization / type transformation support public protocol XMLElementDeserializable { /// Method for deserializing elements from XMLElement static func deserialize(_ element: XMLElement) throws -> Self /* ^^^^^^^^^- take note of the omitted external name in this signature */ } /// Provides XMLElement deserialization / type transformation support public extension XMLElementDeserializable { /** A default implementation that will throw an error if it is called - parameters: - element: the XMLElement to be deserialized - throws: an XMLDeserializationError.ImplementationIsMissing if no implementation is found - returns: this won't ever return because of the error being thrown */ static func deserialize(_ element: XMLElement) throws -> Self { throw XMLDeserializationError.ImplementationIsMissing( method: "XMLElementDeserializable.deserialize(element: XMLElement)") } }
Note the mismatch between the signature of your deserialize
method and the blueprinted one: the latter explicitly omits its external parameter name (_
), whereas yours does not.
We can construct an analogous, minimal example to achieve the same error message.
enum FooError : Error {
case error
}
protocol Foo {
static func bar(_ baz: Int) throws -> Self
}
extension Foo {
static func bar(_ baz: Int) throws -> Self {
throw FooError.error
}
}
// Bar implements its own bar(baz:) method, one which does
// NOT implement bar(_:) from the protocol Foo. This means
// that the throwing erroneous default implementation of
// bar(_:) becomes available to Bar, yielding the same error
// message as in your question
class Bar : Foo {
// does not match the blueprint!
static func bar(baz: Int) throws -> Self {
return value(Bar())
}
private static func value<T>(_ bar: Bar) -> T {
return bar as! T
}
}
// Error!
Which yields the following error message:
error: method '
bar
' in non-final class 'Bar
' must returnSelf
to conform to protocol 'Foo
'static func bar(_ baz: Int) throws -> Self { ...
If we fix the signature of the bar
method in Bar
to match that of the one blueprinted in Foo
, we're no longer prompted with an error
/* ... FooError and Foo as above */
// Bar implements bar(_:) from protocol Foo, which
// means the throwing erroneous default implementation
// of bar(_:) is never in effect, OK
class Bar : Foo {
static func bar(_ baz: Int) throws -> Self {
return value(Bar())
}
private static func value<T>(_ bar: Bar) -> T {
return bar as! T
}
}
To avoid the type inference fix (inferring Bar()
as a valid Self
instance), mark Bar as final
and explicitly annotate the type of Self
/* ... FooError and Foo as above */
final class Bar : Foo {
static func bar(_ baz: Int) throws -> Bar {
return Bar()
}
}
Applied to your use case
Taken the above into account, you need to modify your deserialize
signature into
public static func deserialize(_ element: SWXMLHash.XMLElement) throws -> Self { /* ... */ }
Or, in case you do not plan on subclassing the Element
class itself, marking it final
allowing annotating a concrete return type Element
rather than Self
:
final class Element: XMLElementDeserializable {
public static func deserialize(_ element: SWXMLHash.XMLElement) throws -> Element { /* ... */ }
}
(Note that your current implementation of deserialized
does not make much sense, as it does not make use of the object to be deserialized (internal parameter name element
), but since you mention your example is stripped down, I'll presume this is intended for the example).