I'm using SWXMLHash and have written an extension
on NSDate
for XMLElementDeserializable.
I've followed how the basic types are extended at the end of this file.
What I have looks like this:
import Foundation
import SWXMLHash
struct BlogPost: XMLIndexerDeserializable {
let date: NSDate
static func deserialize(blogPost: XMLIndexer) throws -> BlogPost {
return try BlogPost(
date: blogPost["date"].value()
)
}
}
extension NSDate: XMLElementDeserializable {
/**
Attempts to deserialize XML element content to an NSDate
- element: the XMLElement to be deserialized
- throws: an XMLDeserializationError.TypeConversionFailed if the element cannot be deserialized
- returns: the deserialized NSDate value formatted as "EEE, dd MMM yyyy HH:mm:ss zzz"
*/
public static func deserialize(element: XMLElement) throws -> NSDate {
guard let dateAsString = element.text else {
throw XMLDeserializationError.NodeHasNoValue
}
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz"
let date = dateFormatter.dateFromString(dateAsString)
guard let validDate = date else {
throw XMLDeserializationError.TypeConversionFailed(type: "Date", element: element)
}
return validDate
}
}
Method 'deserialize' in non-final class 'NSDate' must return 'Self' to conform to protocol 'XMLElementDeserializable'
I've looked around S.O. for other answers to the same error and I haven't gleaned much information from them.
Any suggestions would be much appreciated. Thanks!
Okay, this is pretty odd, but the problem exists because NSDate
is a class
instead of a struct
. It apparently takes some work to get a class to conform to a protocol that returns self - it is far easier to get this to work with a struct!
(in Swift 4, this is unnecessary as Date
is a struct)
I'll have to add some additional documentation to show how this can work.
Check out the following code (modified from your example) to see if it works for you:
import Foundation
import SWXMLHash
extension NSDate: XMLElementDeserializable {
// NOTE: for SWXMLHash 3.0 with Swift 3.0, this will be (_ element: XMLElement)
public static func deserialize(element: XMLElement) throws -> Self {
guard let dateAsString = element.text else {
throw XMLDeserializationError.NodeHasNoValue
}
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz"
let date = dateFormatter.dateFromString(dateAsString)
guard let validDate = date else {
throw XMLDeserializationError.TypeConversionFailed(type: "Date", element: element)
}
// NOTE THIS
return value(validDate)
}
// AND THIS
private static func value<T>(date: NSDate) -> T {
return date as! T
}
}
let xml = "<root><elem>Monday, 23 January 2016 12:01:12 111</elem></root>"
let parser = SWXMLHash.parse(xml)
let dt: NSDate = try! parser["root"]["elem"].value()
See also Return instancetype in Swift and Using 'self' in class extension functions in Swift.
NOTE: Added a comment noting that this will look slightly different for SWXMLHash 3.0.